aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-tree.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-tree.cc')
-rw-r--r--gcc/rust/backend/rust-tree.cc5241
1 files changed, 5241 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 6ecc690..d79cd96 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -21,12 +21,37 @@
#include "stringpool.h"
#include "attribs.h"
#include "escaped_string.h"
+#include "libiberty.h"
+#include "stor-layout.h"
+#include "hash-map.h"
+#include "diagnostic.h"
+#include "timevar.h"
+#include "convert.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+#include "function.h"
+#include "gcc-rich-location.h"
+#include "target.h"
+#include "file-prefix-map.h"
+#include "cgraph.h"
+
+#include "output.h"
+
+// forked from gcc/c-family/c-common.cc c_global_trees
+tree c_global_trees[CTI_MAX];
+// forked from gcc/cp/decl.cc cp_global_trees
+tree cp_global_trees[CPTI_MAX];
+
+struct saved_scope *scope_chain;
namespace Rust {
void
mark_exp_read (tree exp)
{
+ char tmp_name[32];
+ ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", 1);
+
if (exp == NULL)
return;
@@ -955,4 +980,5220 @@ rs_type_quals (const_tree type)
return quals;
}
+// forked from gcc/cp/decl.cc cp_global_trees
+
+/* The following symbols are subsumed in the cp_global_trees array, and
+ listed here individually for documentation purposes.
+
+ C++ extensions
+ tree wchar_decl_node;
+
+ tree vtable_entry_type;
+ tree delta_type_node;
+ tree __t_desc_type_node;
+
+ tree class_type_node;
+ tree unknown_type_node;
+
+ Array type `vtable_entry_type[]'
+
+ tree vtbl_type_node;
+ tree vtbl_ptr_type_node;
+
+ Namespaces,
+
+ tree std_node;
+ tree abi_node;
+
+ A FUNCTION_DECL which can call `abort'. Not necessarily the
+ one that the user will declare, but sufficient to be called
+ by routines that want to abort the program.
+
+ tree abort_fndecl;
+
+ Used by RTTI
+ tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
+ tree tinfo_var_id; */
+
+/* The following symbols are subsumed in the c_global_trees array, and
+ listed here individually for documentation purposes.
+
+ INTEGER_TYPE and REAL_TYPE nodes for the standard data types.
+
+ tree short_integer_type_node;
+ tree long_integer_type_node;
+ tree long_long_integer_type_node;
+
+ tree short_unsigned_type_node;
+ tree long_unsigned_type_node;
+ tree long_long_unsigned_type_node;
+
+ tree truthvalue_type_node;
+ tree truthvalue_false_node;
+ tree truthvalue_true_node;
+
+ tree ptrdiff_type_node;
+
+ tree unsigned_char_type_node;
+ tree signed_char_type_node;
+ tree wchar_type_node;
+
+ tree char8_type_node;
+ tree char16_type_node;
+ tree char32_type_node;
+
+ tree float_type_node;
+ tree double_type_node;
+ tree long_double_type_node;
+
+ tree complex_integer_type_node;
+ tree complex_float_type_node;
+ tree complex_double_type_node;
+ tree complex_long_double_type_node;
+
+ tree dfloat32_type_node;
+ tree dfloat64_type_node;
+ tree_dfloat128_type_node;
+
+ tree intQI_type_node;
+ tree intHI_type_node;
+ tree intSI_type_node;
+ tree intDI_type_node;
+ tree intTI_type_node;
+
+ tree unsigned_intQI_type_node;
+ tree unsigned_intHI_type_node;
+ tree unsigned_intSI_type_node;
+ tree unsigned_intDI_type_node;
+ tree unsigned_intTI_type_node;
+
+ tree widest_integer_literal_type_node;
+ tree widest_unsigned_literal_type_node;
+
+ Nodes for types `void *' and `const void *'.
+
+ tree ptr_type_node, const_ptr_type_node;
+
+ Nodes for types `char *' and `const char *'.
+
+ tree string_type_node, const_string_type_node;
+
+ Type `char[SOMENUMBER]'.
+ Used when an array of char is needed and the size is irrelevant.
+
+ tree char_array_type_node;
+
+ Type `wchar_t[SOMENUMBER]' or something like it.
+ Used when a wide string literal is created.
+
+ tree wchar_array_type_node;
+
+ Type `char8_t[SOMENUMBER]' or something like it.
+ Used when a UTF-8 string literal is created.
+
+ tree char8_array_type_node;
+
+ Type `char16_t[SOMENUMBER]' or something like it.
+ Used when a UTF-16 string literal is created.
+
+ tree char16_array_type_node;
+
+ Type `char32_t[SOMENUMBER]' or something like it.
+ Used when a UTF-32 string literal is created.
+
+ tree char32_array_type_node;
+
+ Type `int ()' -- used for implicit declaration of functions.
+
+ tree default_function_type;
+
+ A VOID_TYPE node, packaged in a TREE_LIST.
+
+ tree void_list_node;
+
+ The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__,
+ and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__
+ VAR_DECLS, but C++ does.)
+
+ tree function_name_decl_node;
+ tree pretty_function_name_decl_node;
+ tree c99_function_name_decl_node;
+
+ Stack of nested function name VAR_DECLs.
+
+ tree saved_function_name_decls;
+
+*/
+
+// forked from gcc/cp/module.cc fixed_trees
+
+static GTY (()) vec<tree, va_gc> *fixed_trees;
+
+// forked from gcc/cp/module.cc maybe_add_global
+
+/* VAL is a global tree, add it to the global vec if it is
+ interesting. Add some of its targets, if they too are
+ interesting. We do not add identifiers, as they can be re-found
+ via the identifier hash table. There is a cost to the number of
+ global trees. */
+
+static int
+maybe_add_global (tree val, unsigned &crc)
+{
+ int v = 0;
+
+ if (val && !(TREE_CODE (val) == IDENTIFIER_NODE || TREE_VISITED (val)))
+ {
+ TREE_VISITED (val) = true;
+ crc = crc32_unsigned (crc, fixed_trees->length ());
+ vec_safe_push (fixed_trees, val);
+ v++;
+
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPED))
+ v += maybe_add_global (TREE_TYPE (val), crc);
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (val), TS_TYPE_COMMON))
+ v += maybe_add_global (TYPE_NAME (val), crc);
+ }
+
+ return v;
+}
+
+// forked from gcc/cp/module.cc global_tree_arys
+
+/* Global trees. */
+static const std::pair<tree *, unsigned> global_tree_arys[] = {
+ std::pair<tree *, unsigned> (cp_global_trees, CPTI_MODULE_HWM),
+ std::pair<tree *, unsigned> (c_global_trees, CTI_MODULE_HWM),
+};
+
+// forked from gcc/cp/module.cc init_modules
+
+void
+init_modules ()
+{
+ unsigned crc = 0;
+ vec_alloc (fixed_trees, 200);
+
+ const tree *ptr = global_tree_arys[0].first;
+ unsigned limit = global_tree_arys[0].second;
+ for (unsigned ix = 0; ix != limit; ix++, ptr++)
+ {
+ maybe_add_global (*ptr, crc);
+ }
+
+ ptr = global_tree_arys[1].first;
+ limit = global_tree_arys[1].second;
+ for (unsigned ix = 0; ix != limit; ix++, ptr++)
+ {
+ maybe_add_global (*ptr, crc);
+ }
+}
+
+// forked from gcc/cp/constexpr.cc var_in_constexpr_fn
+
+/* True if T was declared in a function declared to be constexpr, and
+ therefore potentially constant in C++14. */
+
+bool
+var_in_constexpr_fn (tree t)
+{
+ tree ctx = DECL_CONTEXT (t);
+ return (ctx && TREE_CODE (ctx) == FUNCTION_DECL
+ && DECL_DECLARED_CONSTEXPR_P (ctx));
+}
+
+// forked from gcc/cp/name-lookup.cc member_vec_linear_search
+
+/* Linear search of (unordered) MEMBER_VEC for NAME. */
+
+static tree
+member_vec_linear_search (vec<tree, va_gc> *member_vec, tree name)
+{
+ for (int ix = member_vec->length (); ix--;)
+ if (tree binding = (*member_vec)[ix])
+ if (OVL_NAME (binding) == name)
+ return binding;
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/name-lookup.cc member_vec_binary_search
+
+/* Binary search of (ordered) MEMBER_VEC for NAME. */
+
+static tree
+member_vec_binary_search (vec<tree, va_gc> *member_vec, tree name)
+{
+ for (unsigned lo = 0, hi = member_vec->length (); lo < hi;)
+ {
+ unsigned mid = (lo + hi) / 2;
+ tree binding = (*member_vec)[mid];
+ tree binding_name = OVL_NAME (binding);
+
+ if (binding_name > name)
+ hi = mid;
+ else if (binding_name < name)
+ lo = mid + 1;
+ else
+ return binding;
+ }
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/tree.cc is_overloaded_fn
+
+/* 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)
+{
+ STRIP_ANY_LOCATION_WRAPPER (x);
+
+ if (TREE_CODE (x) == COMPONENT_REF)
+ x = TREE_OPERAND (x, 1);
+
+ return OVL_P (x);
+}
+
+// forked from gcc/cp/tree.cc ovl_make
+
+/* Make a raw overload node containing FN. */
+
+tree
+ovl_make (tree fn, tree next)
+{
+ tree result = make_node (OVERLOAD);
+
+ if (TREE_CODE (fn) == OVERLOAD)
+ OVL_NESTED_P (result) = true;
+
+ TREE_TYPE (result) = (next ? 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;
+}
+
+// forked from gcc/cp/name-lookup.cc lookup_add
+
+/* Add a set of new FNS into a lookup. */
+
+tree
+lookup_add (tree fns, tree lookup)
+{
+ if (fns == error_mark_node || lookup == error_mark_node)
+ return error_mark_node;
+
+ lookup = fns;
+
+ return lookup;
+}
+
+// forked from gcc/cp/typeck.cc type_memfn_quals
+
+/* Returns the function-cv-quals for TYPE, which must be a FUNCTION_TYPE or
+ METHOD_TYPE. */
+
+int
+type_memfn_quals (const_tree type)
+{
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ return TYPE_QUALS (type);
+ else if (TREE_CODE (type) == METHOD_TYPE)
+ return rs_type_quals (class_of_this_parm (type));
+ else
+ gcc_unreachable ();
+}
+
+// forked from gcc/cp/pt.cc find_parameter_pack_data
+
+/* Structure used to track the progress of find_parameter_packs_r. */
+struct find_parameter_pack_data
+{
+ /* TREE_LIST that will contain all of the parameter packs found by
+ the traversal. */
+ tree *parameter_packs;
+
+ /* Set of AST nodes that have been visited by the traversal. */
+ hash_set<tree> *visited;
+
+ /* True iff we're making a type pack expansion. */
+ bool type_pack_expansion_p;
+
+ /* True iff we found a subtree that has the extra args mechanism. */
+ bool found_extra_args_tree_p = false;
+};
+
+// forked from gcc/cp/lex.cc conv_type_hasher
+
+/* Hasher for the conversion operator name hash table. */
+struct conv_type_hasher : ggc_ptr_hash<tree_node>
+{
+ /* Hash NODE, an identifier node in the table. TYPE_UID is
+ suitable, as we're not concerned about matching canonicalness
+ here. */
+ static hashval_t hash (tree node)
+ {
+ return (hashval_t) TYPE_UID (TREE_TYPE (node));
+ }
+
+ /* Compare NODE, an identifier node in the table, against TYPE, an
+ incoming TYPE being looked up. */
+ static bool equal (tree node, tree type) { return TREE_TYPE (node) == type; }
+};
+
+static GTY (()) hash_table<conv_type_hasher> *conv_type_names;
+
+// forked from gcc/cp/lex.cc make_conv_op_name
+
+/* Return an identifier for a conversion operator to TYPE. We can get
+ from the returned identifier to the type. We store TYPE, which is
+ not necessarily the canonical type, which allows us to report the
+ form the user used in error messages. All these identifiers are
+ not in the identifier hash table, and have the same string name.
+ These IDENTIFIERS are not in the identifier hash table, and all
+ have the same IDENTIFIER_STRING. */
+
+tree
+make_conv_op_name (tree type)
+{
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ if (conv_type_names == NULL)
+ conv_type_names = hash_table<conv_type_hasher>::create_ggc (31);
+
+ tree *slot
+ = conv_type_names->find_slot_with_hash (type, (hashval_t) TYPE_UID (type),
+ INSERT);
+ tree identifier = *slot;
+ if (!identifier)
+ {
+ /* Create a raw IDENTIFIER outside of the identifier hash
+ table. */
+ identifier = copy_node (conv_op_identifier);
+
+ /* Just in case something managed to bind. */
+ IDENTIFIER_BINDING (identifier) = NULL;
+
+ /* Hang TYPE off the identifier so it can be found easily later
+ when performing conversions. */
+ TREE_TYPE (identifier) = type;
+
+ *slot = identifier;
+ }
+
+ return identifier;
+}
+
+// forked from gcc/cp/pt.cc builtin_pack_fn_p
+
+/* True iff FN is a function representing a built-in variadic parameter
+ pack. */
+
+bool
+builtin_pack_fn_p (tree fn)
+{
+ if (!fn || TREE_CODE (fn) != FUNCTION_DECL
+ || !DECL_IS_UNDECLARED_BUILTIN (fn))
+ return false;
+
+ if (id_equal (DECL_NAME (fn), "__integer_pack"))
+ return true;
+
+ return false;
+}
+
+// forked from gcc/cp/pt.cc builtin_pack_call_p
+
+/* True iff CALL is a call to a function representing a built-in variadic
+ parameter pack. */
+
+static bool
+builtin_pack_call_p (tree call)
+{
+ if (TREE_CODE (call) != CALL_EXPR)
+ return false;
+ return builtin_pack_fn_p (CALL_EXPR_FN (call));
+}
+
+//// forked from gcc/cp/pt.cc has_extra_args_mechanism_p
+//
+///* Return true if the tree T has the extra args mechanism for
+// avoiding partial instantiation. */
+//
+// static bool
+// has_extra_args_mechanism_p (const_tree t)
+//{
+// return false;
+//}
+
+// forked from gcc/cp/pt.cc find_parameter_packs_r
+
+/* Identifies all of the argument packs that occur in a template
+ argument and appends them to the TREE_LIST inside DATA, which is a
+ find_parameter_pack_data structure. This is a subroutine of
+ make_pack_expansion and uses_parameter_packs. */
+static tree
+find_parameter_packs_r (tree *tp, int *walk_subtrees, void *data)
+{
+ tree t = *tp;
+ struct find_parameter_pack_data *ppd
+ = (struct find_parameter_pack_data *) data;
+ bool parameter_pack_p = false;
+
+#define WALK_SUBTREE(NODE) \
+ rs_walk_tree (&(NODE), &find_parameter_packs_r, ppd, ppd->visited)
+
+ /* Don't look through typedefs; we are interested in whether a
+ parameter pack is actually written in the expression/type we're
+ looking at, not the target type. */
+ if (TYPE_P (t) && typedef_variant_p (t))
+ {
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
+ /* Identify whether this is a parameter pack or not. */
+ switch (TREE_CODE (t))
+ {
+ case FIELD_DECL:
+ case PARM_DECL:
+ break;
+
+ case VAR_DECL:
+ break;
+
+ case CALL_EXPR:
+ if (builtin_pack_call_p (t))
+ parameter_pack_p = true;
+ break;
+
+ case BASES:
+ parameter_pack_p = true;
+ break;
+ default:
+ /* Not a parameter pack. */
+ break;
+ }
+
+ if (parameter_pack_p)
+ {
+ /* Add this parameter pack to the list. */
+ *ppd->parameter_packs = tree_cons (NULL_TREE, t, *ppd->parameter_packs);
+ }
+
+ if (TYPE_P (t))
+ rs_walk_tree (&TYPE_CONTEXT (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+
+ /* This switch statement will return immediately if we don't find a
+ parameter pack. ??? Should some of these be in cp_walk_subtrees? */
+ switch (TREE_CODE (t))
+ {
+ case DECL_EXPR: {
+ tree decl = DECL_EXPR_DECL (t);
+ if (is_typedef_decl (decl))
+ /* Since we stop at typedefs above, we need to look through them at
+ the point of the DECL_EXPR. */
+ rs_walk_tree (&DECL_ORIGINAL_TYPE (decl), &find_parameter_packs_r,
+ ppd, ppd->visited);
+ return NULL_TREE;
+ }
+
+ case INTEGER_TYPE:
+ rs_walk_tree (&TYPE_MAX_VALUE (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case IDENTIFIER_NODE:
+ rs_walk_tree (&TREE_TYPE (t), &find_parameter_packs_r, ppd, ppd->visited);
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case DECLTYPE_TYPE: {
+ /* When traversing a DECLTYPE_TYPE_EXPR, we need to set
+ type_pack_expansion_p to false so that any placeholders
+ within the expression don't get marked as parameter packs. */
+ bool type_pack_expansion_p = ppd->type_pack_expansion_p;
+ ppd->type_pack_expansion_p = false;
+ rs_walk_tree (&DECLTYPE_TYPE_EXPR (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+ ppd->type_pack_expansion_p = type_pack_expansion_p;
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
+ case IF_STMT:
+ rs_walk_tree (&IF_COND (t), &find_parameter_packs_r, ppd, ppd->visited);
+ rs_walk_tree (&THEN_CLAUSE (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+ rs_walk_tree (&ELSE_CLAUSE (t), &find_parameter_packs_r, ppd,
+ ppd->visited);
+ /* Don't walk into IF_STMT_EXTRA_ARGS. */
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ WALK_SUBTREE (TYPE_RAISES_EXCEPTIONS (t));
+ break;
+
+ default:
+ return NULL_TREE;
+ }
+
+#undef WALK_SUBTREE
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/typeck.cc type_memfn_rqual
+
+/* Returns the function-ref-qualifier for TYPE */
+
+rs_ref_qualifier
+type_memfn_rqual (const_tree type)
+{
+ gcc_assert (FUNC_OR_METHOD_TYPE_P (type));
+
+ if (!FUNCTION_REF_QUALIFIED (type))
+ return REF_QUAL_NONE;
+ else if (FUNCTION_RVALUE_QUALIFIED (type))
+ return REF_QUAL_RVALUE;
+ else
+ return REF_QUAL_LVALUE;
+}
+
+// forked from gcc/cp/lex.cc maybe_add_lang_type_raw
+
+/* Add a raw lang_type to T, a type, should it need one. */
+
+bool
+maybe_add_lang_type_raw (tree t)
+{
+ if (!RECORD_OR_UNION_CODE_P (TREE_CODE (t)))
+ return false;
+
+ auto *lt = (struct lang_type *) (ggc_internal_cleared_alloc (
+ sizeof (struct lang_type)));
+ TYPE_LANG_SPECIFIC (t) = lt;
+
+ if (GATHER_STATISTICS)
+ {
+ tree_node_counts[(int) lang_type] += 1;
+ tree_node_sizes[(int) lang_type] += sizeof (struct lang_type);
+ }
+
+ return true;
+}
+
+// forked from gcc/c-family/c-lex.cc get_fileinfo
+
+static splay_tree file_info_tree;
+
+struct c_fileinfo *
+get_fileinfo (const char *name)
+{
+ splay_tree_node n;
+ struct c_fileinfo *fi;
+
+ if (!file_info_tree)
+ file_info_tree = splay_tree_new (splay_tree_compare_strings, 0,
+ splay_tree_delete_pointers);
+
+ n = splay_tree_lookup (file_info_tree, (splay_tree_key) name);
+ if (n)
+ return (struct c_fileinfo *) n->value;
+
+ fi = XNEW (struct c_fileinfo);
+ fi->time = 0;
+ fi->interface_only = 0;
+ fi->interface_unknown = 1;
+ splay_tree_insert (file_info_tree, (splay_tree_key) name,
+ (splay_tree_value) fi);
+ return fi;
+}
+
+// forked from gcc/cp/lex.cc cxx_make_type
+
+tree
+cxx_make_type (enum tree_code code MEM_STAT_DECL)
+{
+ tree t = make_node (code PASS_MEM_STAT);
+
+ if (maybe_add_lang_type_raw (t))
+ {
+ /* Set up some flags that give proper default behavior. */
+ struct c_fileinfo *finfo = get_fileinfo (LOCATION_FILE (input_location));
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, finfo->interface_unknown);
+ CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
+ }
+
+ if (code == RECORD_TYPE || code == UNION_TYPE)
+ TYPE_CXX_ODR_P (t) = 1;
+
+ return t;
+}
+
+// forked from gcc/cp/tree.cc build_min_array_type
+
+/* Build an ARRAY_TYPE without laying it out. */
+
+static tree
+build_min_array_type (tree elt_type, tree index_type)
+{
+ tree t = cxx_make_type (ARRAY_TYPE);
+ TREE_TYPE (t) = elt_type;
+ TYPE_DOMAIN (t) = index_type;
+ return t;
+}
+
+// forked from gcc/cp/name-lookup.cc fields_linear_search
+
+/* Linear search of (partially ordered) fields of KLASS for NAME. */
+
+static tree
+fields_linear_search (tree klass, tree name, bool want_type)
+{
+ for (tree fields = TYPE_FIELDS (klass); fields; fields = DECL_CHAIN (fields))
+ {
+ tree decl = fields;
+
+ if (DECL_NAME (decl) != name)
+ continue;
+
+ if (DECL_DECLARES_FUNCTION_P (decl))
+ /* Functions are found separately. */
+ continue;
+
+ if (!want_type || DECL_DECLARES_TYPE_P (decl))
+ return decl;
+ }
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/except.cc canonnothrow_spec_pical_eh_spec
+
+/* Return true iff SPEC is throw() or noexcept(true). */
+
+bool
+nothrow_spec_p (const_tree spec)
+{
+ if (spec == empty_except_spec || spec == noexcept_true_spec)
+ return true;
+
+ gcc_assert (!spec || TREE_VALUE (spec) || spec == noexcept_false_spec
+ || TREE_PURPOSE (spec) == error_mark_node);
+
+ return false;
+}
+
+// forked from gcc/cp/tree.cc may_get_fns
+
+/* Get the overload set FROM refers to. Returns NULL if it's not an
+ overload set. */
+
+tree
+maybe_get_fns (tree from)
+{
+ STRIP_ANY_LOCATION_WRAPPER (from);
+
+ /* A baselink is also considered an overloaded function. */
+ if (TREE_CODE (from) == COMPONENT_REF)
+ from = TREE_OPERAND (from, 1);
+
+ if (OVL_P (from))
+ return from;
+
+ return NULL;
+}
+
+// forked from gcc/cp/tree.cc get_fns
+
+/* 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;
+}
+
+// forked from gcc/cp/tree.cc get_first_fn
+
+/* Return the first function of the overload set FROM refers to. */
+
+tree
+get_first_fn (tree from)
+{
+ return OVL_FIRST (get_fns (from));
+}
+
+// forked from gcc/cp/tree.cc dependent_name
+
+/* X is the CALL_EXPR_FN of a CALL_EXPR. If X represents a dependent name
+ (14.6.2), return the IDENTIFIER_NODE for that name. Otherwise, return
+ NULL_TREE. */
+
+tree
+dependent_name (tree x)
+{
+ /* FIXME a dependent name must be unqualified, but this function doesn't
+ distinguish between qualified and unqualified identifiers. */
+ if (identifier_p (x))
+ return x;
+
+ if (OVL_P (x))
+ return OVL_NAME (x);
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/tree.cc called_fns_equal
+
+/* Subroutine of rs_tree_equal: t1 and t2 are the CALL_EXPR_FNs of two
+ CALL_EXPRS. Return whether they are equivalent. */
+
+static bool
+called_fns_equal (tree t1, tree t2)
+{
+ /* Core 1321: dependent names are equivalent even if the overload sets
+ are different. But do compare explicit template arguments. */
+ tree name1 = dependent_name (t1);
+ tree name2 = dependent_name (t2);
+ if (name1 || name2)
+ {
+ tree targs1 = NULL_TREE, targs2 = NULL_TREE;
+
+ if (name1 != name2)
+ return false;
+
+ /* FIXME dependent_name currently returns an unqualified name regardless
+ of whether the function was named with a qualified- or unqualified-id.
+ Until that's fixed, check that we aren't looking at overload sets from
+ different scopes. */
+ if (is_overloaded_fn (t1) && is_overloaded_fn (t2)
+ && (DECL_CONTEXT (get_first_fn (t1))
+ != DECL_CONTEXT (get_first_fn (t2))))
+ return false;
+
+ return rs_tree_equal (targs1, targs2);
+ }
+ else
+ return rs_tree_equal (t1, t2);
+}
+
+// forked from gcc/cp/tree.cc canonical_eh_spec
+
+/* Return the canonical version of exception-specification RAISES for a C++17
+ function type, for use in type comparison and building TYPE_CANONICAL. */
+
+tree
+canonical_eh_spec (tree raises)
+{
+ if (raises == NULL_TREE)
+ return raises;
+ else if (nothrow_spec_p (raises))
+ /* throw() -> noexcept. */
+ return noexcept_true_spec;
+ else
+ /* For C++17 type matching, anything else -> nothing. */
+ return NULL_TREE;
+}
+
+/* Like cp_tree_operand_length, but takes a tree_code CODE. */
+
+int
+rs_tree_code_length (enum tree_code code)
+{
+ gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
+ switch (code)
+ {
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ return 1;
+
+ case ARRAY_REF:
+ return 2;
+
+ default:
+ return TREE_CODE_LENGTH (code);
+ }
+}
+
+// forked from gcc/cp/tree.cc rs_tree_operand_length
+
+/* Return the number of operands in T that we care about for things like
+ mangling. */
+
+int
+rs_tree_operand_length (const_tree t)
+{
+ enum tree_code code = TREE_CODE (t);
+
+ if (TREE_CODE_CLASS (code) == tcc_vl_exp)
+ return VL_EXP_OPERAND_LENGTH (t);
+
+ return rs_tree_code_length (code);
+}
+
+// forked from gcc/cp/tree.cc cp_tree_equal
+
+/* 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. */
+
+bool
+rs_tree_equal (tree t1, tree t2)
+{
+ enum tree_code code1, code2;
+
+ if (t1 == t2)
+ return true;
+ if (!t1 || !t2)
+ return false;
+
+ code1 = TREE_CODE (t1);
+ code2 = TREE_CODE (t2);
+
+ 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:
+ /* There's only a single VOID_CST node, so we should never reach
+ here. */
+ gcc_unreachable ();
+
+ case INTEGER_CST:
+ return tree_int_cst_equal (t1, t2);
+
+ case REAL_CST:
+ return real_identical (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2));
+
+ case STRING_CST:
+ return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+ && !memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ TREE_STRING_LENGTH (t1));
+
+ case FIXED_CST:
+ return FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), TREE_FIXED_CST (t2));
+
+ case COMPLEX_CST:
+ return rs_tree_equal (TREE_REALPART (t1), TREE_REALPART (t2))
+ && rs_tree_equal (TREE_IMAGPART (t1), TREE_IMAGPART (t2));
+
+ case VECTOR_CST:
+ return operand_equal_p (t1, t2, OEP_ONLY_CONST);
+
+ case CONSTRUCTOR:
+ /* We need to do this when determining whether or not two
+ non-type pointer to member function template arguments
+ are the same. */
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ || CONSTRUCTOR_NELTS (t1) != CONSTRUCTOR_NELTS (t2))
+ return false;
+ {
+ tree field, value;
+ unsigned int i;
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t1), i, field, value)
+ {
+ constructor_elt *elt2 = CONSTRUCTOR_ELT (t2, i);
+ if (!rs_tree_equal (field, elt2->index)
+ || !rs_tree_equal (value, elt2->value))
+ return false;
+ }
+ }
+ return true;
+
+ case TREE_LIST:
+ if (!rs_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)))
+ return false;
+ if (!rs_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2)))
+ return false;
+ return rs_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
+ case SAVE_EXPR:
+ return rs_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case CALL_EXPR: {
+ if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2))
+ return false;
+
+ if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+ return false;
+
+ call_expr_arg_iterator iter1, iter2;
+ init_call_expr_arg_iterator (t1, &iter1);
+ init_call_expr_arg_iterator (t2, &iter2);
+ if (iter1.n != iter2.n)
+ return false;
+
+ while (more_call_expr_args_p (&iter1))
+ {
+ tree arg1 = next_call_expr_arg (&iter1);
+ tree arg2 = next_call_expr_arg (&iter2);
+
+ gcc_checking_assert (arg1 && arg2);
+ if (!rs_tree_equal (arg1, arg2))
+ return false;
+ }
+
+ return true;
+ }
+
+ case TARGET_EXPR: {
+ tree o1 = TREE_OPERAND (t1, 0);
+ tree o2 = TREE_OPERAND (t2, 0);
+
+ /* Special case: if either target is an unallocated VAR_DECL,
+ it means that it's going to be unified with whatever the
+ TARGET_EXPR is really supposed to initialize, so treat it
+ as being equivalent to anything. */
+ if (VAR_P (o1) && DECL_NAME (o1) == NULL_TREE && !DECL_RTL_SET_P (o1))
+ /*Nop*/;
+ else if (VAR_P (o2) && DECL_NAME (o2) == NULL_TREE
+ && !DECL_RTL_SET_P (o2))
+ /*Nop*/;
+ else if (!rs_tree_equal (o1, o2))
+ return false;
+
+ return rs_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+ }
+
+ case PARM_DECL:
+ /* For comparing uses of parameters in late-specified return types
+ with an out-of-class definition of the function, but can also come
+ up for expressions that involve 'this' in a member function
+ template. */
+
+ if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ {
+ if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
+ return false;
+ if (CONSTRAINT_VAR_P (t1) ^ CONSTRAINT_VAR_P (t2))
+ return false;
+ if (DECL_ARTIFICIAL (t1)
+ || (DECL_PARM_LEVEL (t1) == DECL_PARM_LEVEL (t2)
+ && DECL_PARM_INDEX (t1) == DECL_PARM_INDEX (t2)))
+ return true;
+ }
+ return false;
+
+ case VAR_DECL:
+ case CONST_DECL:
+ case FIELD_DECL:
+ case FUNCTION_DECL:
+ case IDENTIFIER_NODE:
+ case SSA_NAME:
+ return false;
+
+ case TREE_VEC:
+ return true;
+
+ case NON_LVALUE_EXPR:
+ case VIEW_CONVERT_EXPR:
+ /* Used for location wrappers with possibly NULL types. */
+ if (!TREE_TYPE (t1) || !TREE_TYPE (t2))
+ {
+ if (TREE_TYPE (t1) || TREE_TYPE (t2))
+ return false;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ switch (TREE_CODE_CLASS (code1))
+ {
+ case tcc_unary:
+ case tcc_binary:
+ case tcc_comparison:
+ case tcc_expression:
+ case tcc_vl_exp:
+ case tcc_reference:
+ case tcc_statement: {
+ int n = rs_tree_operand_length (t1);
+ if (TREE_CODE_CLASS (code1) == tcc_vl_exp
+ && n != TREE_OPERAND_LENGTH (t2))
+ return false;
+
+ for (int i = 0; i < n; ++i)
+ if (!rs_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i)))
+ return false;
+
+ return true;
+ }
+
+ case tcc_type:
+ return same_type_p (t1, t2);
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* We can get here with --disable-checking. */
+ return false;
+}
+
+// forked from gcc/cp/class.cc publicly_uniquely_derived_p
+
+/* TRUE iff TYPE is publicly & uniquely derived from PARENT. */
+
+bool
+publicly_uniquely_derived_p (tree parent, tree type)
+{
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_except_types
+
+/* Compare two exception specifier types for exactness or subsetness, if
+ allowed. Returns false for mismatch, true for match (same, or
+ derived and !exact).
+
+ [except.spec] "If a class X ... objects of class X or any class publicly
+ and unambiguously derived from X. Similarly, if a pointer type Y * ...
+ exceptions of type Y * or that are pointers to any type publicly and
+ unambiguously derived from Y. Otherwise a function only allows exceptions
+ that have the same type ..."
+ This does not mention cv qualifiers and is different to what throw
+ [except.throw] and catch [except.catch] will do. They will ignore the
+ top level cv qualifiers, and allow qualifiers in the pointer to class
+ example.
+
+ We implement the letter of the standard. */
+
+static bool
+comp_except_types (tree a, tree b, bool exact)
+{
+ if (same_type_p (a, b))
+ return true;
+ else if (!exact)
+ {
+ if (rs_type_quals (a) || rs_type_quals (b))
+ return false;
+
+ if (TYPE_PTR_P (a) && TYPE_PTR_P (b))
+ {
+ a = TREE_TYPE (a);
+ b = TREE_TYPE (b);
+ if (rs_type_quals (a) || rs_type_quals (b))
+ return false;
+ }
+
+ if (TREE_CODE (a) != RECORD_TYPE || TREE_CODE (b) != RECORD_TYPE)
+ return false;
+
+ if (publicly_uniquely_derived_p (a, b))
+ return true;
+ }
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_except_specs
+
+/* Return true if TYPE1 and TYPE2 are equivalent exception specifiers.
+ If EXACT is ce_derived, T2 can be stricter than T1 (according to 15.4/5).
+ If EXACT is ce_type, the C++17 type compatibility rules apply.
+ If EXACT is ce_normal, the compatibility rules in 15.4/3 apply.
+ If EXACT is ce_exact, the specs must be exactly the same. Exception lists
+ are unordered, but we've already filtered out duplicates. Most lists will
+ be in order, we should try to make use of that. */
+
+bool
+comp_except_specs (const_tree t1, const_tree t2, int exact)
+{
+ const_tree probe;
+ const_tree base;
+ int length = 0;
+
+ if (t1 == t2)
+ return true;
+
+ /* First handle noexcept. */
+ if (exact < ce_exact)
+ {
+ if (exact == ce_type
+ && (canonical_eh_spec (CONST_CAST_TREE (t1))
+ == canonical_eh_spec (CONST_CAST_TREE (t2))))
+ return true;
+
+ /* noexcept(false) is compatible with no exception-specification,
+ and less strict than any spec. */
+ if (t1 == noexcept_false_spec)
+ return t2 == NULL_TREE || exact == ce_derived;
+ /* Even a derived noexcept(false) is compatible with no
+ exception-specification. */
+ if (t2 == noexcept_false_spec)
+ return t1 == NULL_TREE;
+
+ /* Otherwise, if we aren't looking for an exact match, noexcept is
+ equivalent to throw(). */
+ if (t1 == noexcept_true_spec)
+ t1 = empty_except_spec;
+ if (t2 == noexcept_true_spec)
+ t2 = empty_except_spec;
+ }
+
+ /* If any noexcept is left, it is only comparable to itself;
+ either we're looking for an exact match or we're redeclaring a
+ template with dependent noexcept. */
+ if ((t1 && TREE_PURPOSE (t1)) || (t2 && TREE_PURPOSE (t2)))
+ return (t1 && t2 && rs_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2)));
+
+ if (t1 == NULL_TREE) /* T1 is ... */
+ return t2 == NULL_TREE || exact == ce_derived;
+ if (!TREE_VALUE (t1)) /* t1 is EMPTY */
+ return t2 != NULL_TREE && !TREE_VALUE (t2);
+ if (t2 == NULL_TREE) /* T2 is ... */
+ return false;
+ if (TREE_VALUE (t1) && !TREE_VALUE (t2)) /* T2 is EMPTY, T1 is not */
+ return exact == ce_derived;
+
+ /* Neither set is ... or EMPTY, make sure each part of T2 is in T1.
+ Count how many we find, to determine exactness. For exact matching and
+ ordered T1, T2, this is an O(n) operation, otherwise its worst case is
+ O(nm). */
+ for (base = t1; t2 != NULL_TREE; t2 = TREE_CHAIN (t2))
+ {
+ for (probe = base; probe != NULL_TREE; probe = TREE_CHAIN (probe))
+ {
+ tree a = TREE_VALUE (probe);
+ tree b = TREE_VALUE (t2);
+
+ if (comp_except_types (a, b, exact))
+ {
+ if (probe == base && exact > ce_derived)
+ base = TREE_CHAIN (probe);
+ length++;
+ break;
+ }
+ }
+ if (probe == NULL_TREE)
+ return false;
+ }
+ return exact == ce_derived || base == NULL_TREE || length == list_length (t1);
+}
+
+// forked from gcc/cp/typeck.cc compparms
+
+/* Subroutines of `comptypes'. */
+
+/* Return true if two parameter type lists PARMS1 and PARMS2 are
+ equivalent in the sense that functions with those parameter types
+ can have equivalent types. The two lists must be equivalent,
+ element by element. */
+
+bool
+compparms (const_tree parms1, const_tree parms2)
+{
+ const_tree t1, t2;
+
+ /* An unspecified parmlist matches any specified parmlist
+ whose argument types don't need default promotions. */
+
+ for (t1 = parms1, t2 = parms2; t1 || t2;
+ t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+ {
+ /* If one parmlist is shorter than the other,
+ they fail to match. */
+ if (!t1 || !t2)
+ return false;
+ if (!same_type_p (TREE_VALUE (t1), TREE_VALUE (t2)))
+ return false;
+ }
+ return true;
+}
+
+/* Set TYPE_CANONICAL like build_array_type_1, but using
+ build_cplus_array_type. */
+
+static void
+set_array_type_canon (tree t, tree elt_type, tree index_type, bool dep)
+{
+ /* 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,
+ dep);
+ else
+ TYPE_CANONICAL (t) = t;
+}
+
+// forked from gcc/cp/tree.cc cplus_array_info
+
+struct cplus_array_info
+{
+ tree type;
+ tree domain;
+};
+
+// forked from gcc/cp/tree.cc cplus_array_hasher
+
+struct cplus_array_hasher : ggc_ptr_hash<tree_node>
+{
+ typedef cplus_array_info *compare_type;
+
+ static hashval_t hash (tree t);
+ static bool equal (tree, cplus_array_info *);
+};
+
+/* Hash an ARRAY_TYPE. K is really of type `tree'. */
+
+hashval_t
+cplus_array_hasher::hash (tree t)
+{
+ hashval_t hash;
+
+ hash = TYPE_UID (TREE_TYPE (t));
+ if (TYPE_DOMAIN (t))
+ hash ^= TYPE_UID (TYPE_DOMAIN (t));
+ return hash;
+}
+
+/* Compare two ARRAY_TYPEs. K1 is really of type `tree', K2 is really
+ of type `cplus_array_info*'. */
+
+bool
+cplus_array_hasher::equal (tree t1, cplus_array_info *t2)
+{
+ return (TREE_TYPE (t1) == t2->type && TYPE_DOMAIN (t1) == t2->domain);
+}
+
+// forked from gcc/cp/tree.cc cplus_array_htab
+
+/* Hash table containing dependent array types, which are unsuitable for
+ the language-independent type hash table. */
+static GTY (()) hash_table<cplus_array_hasher> *cplus_array_htab;
+
+// forked from gcc/cp/tree.cc is_byte_access_type
+
+/* Returns true if TYPE is char, unsigned char, or std::byte. */
+
+bool
+is_byte_access_type (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+ if (type == char_type_node || type == unsigned_char_type_node)
+ return true;
+
+ return (TREE_CODE (type) == ENUMERAL_TYPE && TYPE_CONTEXT (type) == std_node
+ && !strcmp ("byte", TYPE_NAME_STRING (type)));
+}
+
+// forked from gcc/cp/tree.cc build_cplus_array_type
+
+/* Like build_array_type, but handle special C++ semantics: an array of a
+ variant element type is a variant of the array of the main variant of
+ the element type. IS_DEPENDENT is -ve if we should determine the
+ dependency. Otherwise its bool value indicates dependency. */
+
+tree
+build_cplus_array_type (tree elt_type, tree index_type, int dependent)
+{
+ tree t;
+
+ if (elt_type == error_mark_node || index_type == error_mark_node)
+ return error_mark_node;
+
+ if (dependent < 0)
+ dependent = 0;
+
+ if (elt_type != TYPE_MAIN_VARIANT (elt_type))
+ /* Start with an array of the TYPE_MAIN_VARIANT. */
+ t = build_cplus_array_type (TYPE_MAIN_VARIANT (elt_type), index_type,
+ dependent);
+ else if (dependent)
+ {
+ /* Since type_hash_canon calls layout_type, we need to use our own
+ hash table. */
+ cplus_array_info cai;
+ hashval_t hash;
+
+ if (cplus_array_htab == NULL)
+ cplus_array_htab = hash_table<cplus_array_hasher>::create_ggc (61);
+
+ hash = TYPE_UID (elt_type);
+ if (index_type)
+ hash ^= TYPE_UID (index_type);
+ cai.type = elt_type;
+ cai.domain = index_type;
+
+ tree *e = cplus_array_htab->find_slot_with_hash (&cai, hash, INSERT);
+ if (*e)
+ /* We have found the type: we're done. */
+ return (tree) *e;
+ else
+ {
+ /* Build a new array type. */
+ t = build_min_array_type (elt_type, index_type);
+
+ /* Store it in the hash table. */
+ *e = t;
+
+ /* Set the canonical type for this new node. */
+ set_array_type_canon (t, elt_type, index_type, dependent);
+
+ /* Mark it as dependent now, this saves time later. */
+ TYPE_DEPENDENT_P_VALID (t) = true;
+ TYPE_DEPENDENT_P (t) = true;
+ }
+ }
+ else
+ {
+ bool typeless_storage = is_byte_access_type (elt_type);
+ t = build_array_type (elt_type, index_type, typeless_storage);
+
+ /* Mark as non-dependenty now, this will save time later. */
+ TYPE_DEPENDENT_P_VALID (t) = true;
+ }
+
+ /* Now check whether we already have this array variant. */
+ if (elt_type != TYPE_MAIN_VARIANT (elt_type))
+ {
+ tree m = t;
+ for (t = m; t; t = TYPE_NEXT_VARIANT (t))
+ if (TREE_TYPE (t) == elt_type && TYPE_NAME (t) == NULL_TREE
+ && TYPE_ATTRIBUTES (t) == NULL_TREE)
+ break;
+ if (!t)
+ {
+ t = build_min_array_type (elt_type, index_type);
+ /* Mark dependency now, this saves time later. */
+ TYPE_DEPENDENT_P_VALID (t) = true;
+ TYPE_DEPENDENT_P (t) = dependent;
+ set_array_type_canon (t, elt_type, index_type, dependent);
+ if (!dependent)
+ {
+ layout_type (t);
+ /* Make sure sizes are shared with the main variant.
+ layout_type can't be called after setting TYPE_NEXT_VARIANT,
+ as it will overwrite alignment etc. of all variants. */
+ TYPE_SIZE (t) = TYPE_SIZE (m);
+ TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (m);
+ TYPE_TYPELESS_STORAGE (t) = TYPE_TYPELESS_STORAGE (m);
+ }
+
+ TYPE_MAIN_VARIANT (t) = m;
+ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
+ TYPE_NEXT_VARIANT (m) = t;
+ }
+ }
+
+ /* Avoid spurious warnings with VLAs (c++/54583). */
+ if (TYPE_SIZE (t) && EXPR_P (TYPE_SIZE (t)))
+ suppress_warning (TYPE_SIZE (t), OPT_Wunused);
+
+ /* Push these needs up to the ARRAY_TYPE so that initialization takes
+ place more easily. */
+ bool needs_ctor
+ = (TYPE_NEEDS_CONSTRUCTING (t) = TYPE_NEEDS_CONSTRUCTING (elt_type));
+ bool needs_dtor = (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+ = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type));
+
+ if (!dependent && t == TYPE_MAIN_VARIANT (t) && !COMPLETE_TYPE_P (t)
+ && COMPLETE_TYPE_P (elt_type))
+ {
+ /* The element type has been completed since the last time we saw
+ this array type; update the layout and 'tor flags for any variants
+ that need it. */
+ layout_type (t);
+ for (tree v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
+ {
+ TYPE_NEEDS_CONSTRUCTING (v) = needs_ctor;
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR (v) = needs_dtor;
+ }
+ }
+
+ return t;
+}
+
+// forked from gcc/cp/tree.cc cp_build_qualified_type_real
+
+/* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles
+ arrays correctly. In particular, if TYPE is an array of T's, and
+ TYPE_QUALS is non-empty, returns an array of qualified T's.
+
+ FLAGS determines how to deal with ill-formed qualifications. If
+ tf_ignore_bad_quals is set, then bad qualifications are dropped
+ (this is permitted if TYPE was introduced via a typedef or template
+ type parameter). If bad qualifications are dropped and tf_warning
+ is set, then a warning is issued for non-const qualifications. If
+ tf_ignore_bad_quals is not set and tf_error is not set, we
+ return error_mark_node. Otherwise, we issue an error, and ignore
+ the qualifications.
+
+ Qualification of a reference type is valid when the reference came
+ via a typedef or template type argument. [dcl.ref] No such
+ dispensation is provided for qualifying a function type. [dcl.fct]
+ DR 295 queries this and the proposed resolution brings it into line
+ with qualifying a reference. We implement the DR. We also behave
+ in a similar manner for restricting non-pointer types. */
+
+tree
+rs_build_qualified_type_real (tree type, int type_quals,
+ tsubst_flags_t complain)
+{
+ tree result;
+ int bad_quals = TYPE_UNQUALIFIED;
+
+ if (type == error_mark_node)
+ return type;
+
+ if (type_quals == rs_type_quals (type))
+ return type;
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ /* In C++, the qualification really applies to the array element
+ type. Obtain the appropriately qualified element type. */
+ tree t;
+ tree element_type
+ = rs_build_qualified_type_real (TREE_TYPE (type), type_quals, complain);
+
+ if (element_type == error_mark_node)
+ return error_mark_node;
+
+ /* See if we already have an identically qualified type. Tests
+ should be equivalent to those in check_qualified_type. */
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ if (TREE_TYPE (t) == element_type && TYPE_NAME (t) == TYPE_NAME (type)
+ && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+ && attribute_list_equal (TYPE_ATTRIBUTES (t),
+ TYPE_ATTRIBUTES (type)))
+ break;
+
+ if (!t)
+ {
+ /* If we already know the dependentness, tell the array type
+ constructor. This is important for module streaming, as we cannot
+ dynamically determine that on read in. */
+ t = build_cplus_array_type (element_type, TYPE_DOMAIN (type),
+ TYPE_DEPENDENT_P_VALID (type)
+ ? int (TYPE_DEPENDENT_P (type))
+ : -1);
+
+ /* Keep the typedef name. */
+ if (TYPE_NAME (t) != TYPE_NAME (type))
+ {
+ t = build_variant_type_copy (t);
+ TYPE_NAME (t) = TYPE_NAME (type);
+ SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
+ TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
+ }
+ }
+
+ /* Even if we already had this variant, we update
+ TYPE_NEEDS_CONSTRUCTING and TYPE_HAS_NONTRIVIAL_DESTRUCTOR in case
+ they changed since the variant was originally created.
+
+ This seems hokey; if there is some way to use a previous
+ variant *without* coming through here,
+ TYPE_NEEDS_CONSTRUCTING will never be updated. */
+ TYPE_NEEDS_CONSTRUCTING (t)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (element_type));
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+ = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (element_type));
+ return t;
+ }
+
+ /* A reference or method type shall not be cv-qualified.
+ [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. */
+
+ /* [dcl.ref/1] Cv-qualified references are ill-formed except when
+ the cv-qualifiers are introduced through the use of a typedef-name
+ ([dcl.typedef], [temp.param]) or decltype-specifier
+ ([dcl.type.decltype]),in which case the cv-qualifiers are
+ ignored. */
+ if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)
+ && (TYPE_REF_P (type) || FUNC_OR_METHOD_TYPE_P (type)))
+ {
+ if (TYPE_REF_P (type)
+ && (!typedef_variant_p (type) || FUNC_OR_METHOD_TYPE_P (type)))
+ bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+ type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+ }
+
+ /* But preserve any function-cv-quals on a FUNCTION_TYPE. */
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ type_quals |= type_memfn_quals (type);
+
+ /* A restrict-qualified type must be a pointer (or reference)
+ to object or incomplete type. */
+ if ((type_quals & TYPE_QUAL_RESTRICT) && TREE_CODE (type) != TYPENAME_TYPE
+ && !INDIRECT_TYPE_P (type))
+ {
+ bad_quals |= TYPE_QUAL_RESTRICT;
+ type_quals &= ~TYPE_QUAL_RESTRICT;
+ }
+
+ if (bad_quals == TYPE_UNQUALIFIED || (complain & tf_ignore_bad_quals))
+ /*OK*/;
+ else if (!(complain & tf_error))
+ return error_mark_node;
+ else
+ {
+ tree bad_type = build_qualified_type (ptr_type_node, bad_quals);
+ error ("%qV qualifiers cannot be applied to %qT", bad_type, type);
+ }
+
+ /* Retrieve (or create) the appropriately qualified variant. */
+ result = build_qualified_type (type, type_quals);
+
+ return result;
+}
+
+// forked from gcc/cp/c-common.cc vector_targets_convertible_p
+
+/* vector_targets_convertible_p is used for vector pointer types. The
+ callers perform various checks that the qualifiers are satisfactory,
+ while OTOH vector_targets_convertible_p ignores the number of elements
+ in the vectors. That's fine with vector pointers as we can consider,
+ say, a vector of 8 elements as two consecutive vectors of 4 elements,
+ and that does not require and conversion of the pointer values.
+ In contrast, vector_types_convertible_p and
+ vector_types_compatible_elements_p are used for vector value types. */
+/* True if pointers to distinct types T1 and T2 can be converted to
+ each other without an explicit cast. Only returns true for opaque
+ vector types. */
+bool
+vector_targets_convertible_p (const_tree t1, const_tree t2)
+{
+ if (VECTOR_TYPE_P (t1) && VECTOR_TYPE_P (t2)
+ && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
+ && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
+ return true;
+
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc comp_array_types
+
+/* Compare the array types T1 and T2. CB says how we should behave when
+ comparing array bounds: bounds_none doesn't allow dimensionless arrays,
+ bounds_either says than any array can be [], bounds_first means that
+ onlt T1 can be an array with unknown bounds. STRICT is true if
+ qualifiers must match when comparing the types of the array elements. */
+
+static bool
+comp_array_types (const_tree t1, const_tree t2, compare_bounds_t cb,
+ bool strict)
+{
+ tree d1;
+ tree d2;
+ tree max1, max2;
+
+ if (t1 == t2)
+ return true;
+
+ /* The type of the array elements must be the same. */
+ if (strict ? !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2))
+ : !similar_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+
+ d1 = TYPE_DOMAIN (t1);
+ d2 = TYPE_DOMAIN (t2);
+
+ if (d1 == d2)
+ return true;
+
+ /* If one of the arrays is dimensionless, and the other has a
+ dimension, they are of different types. However, it is valid to
+ write:
+
+ extern int a[];
+ int a[3];
+
+ by [basic.link]:
+
+ declarations for an array object can specify
+ array types that differ by the presence or absence of a major
+ array bound (_dcl.array_). */
+ if (!d1 && d2)
+ return cb >= bounds_either;
+ else if (d1 && !d2)
+ return cb == bounds_either;
+
+ /* Check that the dimensions are the same. */
+
+ if (!rs_tree_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2)))
+ return false;
+ max1 = TYPE_MAX_VALUE (d1);
+ max2 = TYPE_MAX_VALUE (d2);
+
+ if (!rs_tree_equal (max1, max2))
+ return false;
+
+ return true;
+}
+
+// forked from gcc/cp/typeck.cc same_type_ignoring_top_level_qualifiers_p
+
+/* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
+ top-level qualifiers. */
+
+bool
+same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
+{
+ if (type1 == error_mark_node || type2 == error_mark_node)
+ return false;
+ if (type1 == type2)
+ return true;
+
+ type1 = rs_build_qualified_type (type1, TYPE_UNQUALIFIED);
+ type2 = rs_build_qualified_type (type2, TYPE_UNQUALIFIED);
+ return same_type_p (type1, type2);
+}
+
+// forked from gcc/cp/typeck.cc comp_ptr_ttypes_const
+
+/* Return true if TO and FROM (both of which are POINTER_TYPEs or
+ pointer-to-member types) are the same, ignoring cv-qualification at
+ all levels. CB says how we should behave when comparing array bounds. */
+
+bool
+comp_ptr_ttypes_const (tree to, tree from, compare_bounds_t cb)
+{
+ bool is_opaque_pointer = false;
+
+ for (;; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return false;
+
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && same_type_p (TYPE_OFFSET_BASETYPE (from),
+ TYPE_OFFSET_BASETYPE (to)))
+ continue;
+
+ if (VECTOR_TYPE_P (to))
+ is_opaque_pointer = vector_targets_convertible_p (to, from);
+
+ if (TREE_CODE (to) == ARRAY_TYPE
+ /* Ignore cv-qualification, but if we see e.g. int[3] and int[4],
+ we must fail. */
+ && !comp_array_types (to, from, cb, /*strict=*/false))
+ return false;
+
+ /* CWG 330 says we need to look through arrays. */
+ if (!TYPE_PTR_P (to) && TREE_CODE (to) != ARRAY_TYPE)
+ return (is_opaque_pointer
+ || same_type_ignoring_top_level_qualifiers_p (to, from));
+ }
+}
+
+// forked from gcc/cp/typeck.cc similar_type_p
+
+/* Returns nonzero iff TYPE1 and TYPE2 are similar, as per [conv.qual]. */
+
+bool
+similar_type_p (tree type1, tree type2)
+{
+ if (type1 == error_mark_node || type2 == error_mark_node)
+ return false;
+
+ /* Informally, two types are similar if, ignoring top-level cv-qualification:
+ * they are the same type; or
+ * they are both pointers, and the pointed-to types are similar; or
+ * they are both pointers to member of the same class, and the types of
+ the pointed-to members are similar; or
+ * they are both arrays of the same size or both arrays of unknown bound,
+ and the array element types are similar. */
+
+ if (same_type_ignoring_top_level_qualifiers_p (type1, type2))
+ return true;
+
+ if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+ || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
+ || (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (type2) == ARRAY_TYPE))
+ return comp_ptr_ttypes_const (type1, type2, bounds_either);
+
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc structural_comptypes
+// note: this fork only handles strict == COMPARE_STRICT
+// if you pass in any other value for strict i.e. COMPARE_BASE,
+// COMPARE_DERIVED, COMPARE_REDECLARATION or COMPARE_STRUCTURAL
+// see the original function in gcc/cp/typeck.cc and port the required bits
+// specifically under case UNION_TYPE.
+
+/* Subroutine in comptypes. */
+
+static bool
+structural_comptypes (tree t1, tree t2, int strict)
+{
+ /* Both should be types that are not obviously the same. */
+ gcc_checking_assert (t1 != t2 && TYPE_P (t1) && TYPE_P (t2));
+
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
+ /* Different classes of types can't be compatible. */
+ if (TREE_CODE (t1) != TREE_CODE (t2))
+ return false;
+
+ /* Qualifiers must match. For array types, we will check when we
+ recur on the array element types. */
+ if (TREE_CODE (t1) != ARRAY_TYPE && rs_type_quals (t1) != rs_type_quals (t2))
+ return false;
+ if (TREE_CODE (t1) == FUNCTION_TYPE
+ && type_memfn_quals (t1) != type_memfn_quals (t2))
+ return false;
+ /* Need to check this before TYPE_MAIN_VARIANT.
+ FIXME function qualifiers should really change the main variant. */
+ if (FUNC_OR_METHOD_TYPE_P (t1))
+ {
+ if (type_memfn_rqual (t1) != type_memfn_rqual (t2))
+ return false;
+ if (/* cxx_dialect >= cxx17 && */
+ !comp_except_specs (TYPE_RAISES_EXCEPTIONS (t1),
+ TYPE_RAISES_EXCEPTIONS (t2), ce_type))
+ return false;
+ }
+
+ /* Allow for two different type nodes which have essentially the same
+ definition. Note that we already checked for equality of the type
+ qualifiers (just above). */
+ if (TREE_CODE (t1) != ARRAY_TYPE
+ && TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
+ return true;
+
+ /* Compare the types. Return false on known not-same. Break on not
+ known. Never return true from this switch -- you'll break
+ specialization comparison. */
+ switch (TREE_CODE (t1))
+ {
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ /* All void and bool types are the same. */
+ break;
+
+ case OPAQUE_TYPE:
+ case INTEGER_TYPE:
+ case FIXED_POINT_TYPE:
+ case REAL_TYPE:
+ /* With these nodes, we can't determine type equivalence by
+ looking at what is stored in the nodes themselves, because
+ two nodes might have different TYPE_MAIN_VARIANTs but still
+ represent the same type. For example, wchar_t and int could
+ have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE,
+ TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs
+ and are distinct types. On the other hand, int and the
+ following typedef
+
+ typedef int INT __attribute((may_alias));
+
+ have identical properties, different TYPE_MAIN_VARIANTs, but
+ represent the same type. The canonical type system keeps
+ track of equivalence in this case, so we fall back on it. */
+ if (TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
+ return false;
+
+ /* We don't need or want the attribute comparison. */
+ return true;
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ return false;
+
+ case OFFSET_TYPE:
+ if (!comptypes (TYPE_OFFSET_BASETYPE (t1), TYPE_OFFSET_BASETYPE (t2),
+ strict & ~COMPARE_REDECLARATION))
+ return false;
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
+
+ case REFERENCE_TYPE:
+ if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2))
+ return false;
+ /* fall through to checks for pointer types */
+ gcc_fallthrough ();
+
+ case POINTER_TYPE:
+ if (TYPE_MODE (t1) != TYPE_MODE (t2)
+ || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
+
+ case METHOD_TYPE:
+ case FUNCTION_TYPE:
+ /* Exception specs and memfn_rquals were checked above. */
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ if (!compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)))
+ return false;
+ break;
+
+ case ARRAY_TYPE:
+ /* Target types must match incl. qualifiers. */
+ if (!comp_array_types (t1, t2,
+ ((strict & COMPARE_REDECLARATION) ? bounds_either
+ : bounds_none),
+ /*strict=*/true))
+ return false;
+ break;
+
+ case COMPLEX_TYPE:
+ if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
+
+ case VECTOR_TYPE:
+ if (gnu_vector_type_p (t1) != gnu_vector_type_p (t2)
+ || maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
+ || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ /* If we get here, we know that from a target independent POV the
+ types are the same. Make sure the target attributes are also
+ the same. */
+ if (!comp_type_attributes (t1, t2))
+ return false;
+
+ return true;
+}
+
+// forked from gcc/cp/typeck.cc comptypes
+
+/* Return true if T1 and T2 are related as allowed by STRICT. STRICT
+ is a bitwise-or of the COMPARE_* flags. */
+
+bool
+comptypes (tree t1, tree t2, int strict)
+{
+ gcc_checking_assert (t1 && t2);
+
+ /* TYPE_ARGUMENT_PACKS are not really types. */
+ gcc_checking_assert (TREE_CODE (t1) != TYPE_ARGUMENT_PACK
+ && TREE_CODE (t2) != TYPE_ARGUMENT_PACK);
+
+ if (t1 == t2)
+ return true;
+
+ /* Suppress errors caused by previously reported errors. */
+ if (t1 == error_mark_node || t2 == error_mark_node)
+ return false;
+
+ if (strict == COMPARE_STRICT)
+ {
+ if (TYPE_STRUCTURAL_EQUALITY_P (t1) || TYPE_STRUCTURAL_EQUALITY_P (t2))
+ /* At least one of the types requires structural equality, so
+ perform a deep check. */
+ return structural_comptypes (t1, t2, strict);
+
+ if (flag_checking && param_use_canonical_types)
+ {
+ bool result = structural_comptypes (t1, t2, strict);
+
+ if (result && TYPE_CANONICAL (t1) != TYPE_CANONICAL (t2))
+ /* The two types are structurally equivalent, but their
+ canonical types were different. This is a failure of the
+ canonical type propagation code.*/
+ internal_error (
+ "canonical types differ for identical types %qT and %qT", t1, t2);
+ else if (!result && TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2))
+ /* Two types are structurally different, but the canonical
+ types are the same. This means we were over-eager in
+ assigning canonical types. */
+ internal_error (
+ "same canonical type node for different types %qT and %qT", t1,
+ t2);
+
+ return result;
+ }
+ if (!flag_checking && param_use_canonical_types)
+ return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2);
+ else
+ return structural_comptypes (t1, t2, strict);
+ }
+ else if (strict == COMPARE_STRUCTURAL)
+ return structural_comptypes (t1, t2, COMPARE_STRICT);
+ else
+ return structural_comptypes (t1, t2, strict);
+}
+
+// forked from gcc/cp/decl.cc next_initializable_field
+
+/* FIELD is an element of TYPE_FIELDS or NULL. In the former case, the value
+ returned is the next FIELD_DECL (possibly FIELD itself) that can be
+ initialized. If there are no more such fields, the return value
+ will be NULL. */
+
+tree
+next_initializable_field (tree field)
+{
+ while (field
+ && (TREE_CODE (field) != FIELD_DECL || DECL_UNNAMED_BIT_FIELD (field)
+ || (DECL_ARTIFICIAL (field)
+ /* Don't skip vptr fields. We might see them when we're
+ called from reduced_constant_expression_p. */
+ && !DECL_VIRTUAL_P (field))))
+ field = DECL_CHAIN (field);
+
+ return field;
+}
+
+// forked from gcc/cp/call.cc sufficient_parms_p
+
+/* Returns nonzero if PARMLIST consists of only default parms,
+ ellipsis, and/or undeduced parameter packs. */
+
+bool
+sufficient_parms_p (const_tree parmlist)
+{
+ for (; parmlist && parmlist != void_list_node;
+ parmlist = TREE_CHAIN (parmlist))
+ if (!TREE_PURPOSE (parmlist))
+ return false;
+ return true;
+}
+
+// forked from gcc/cp/class.cc default_ctor_p
+
+/* Returns true if FN is a default constructor. */
+
+bool
+default_ctor_p (const_tree fn)
+{
+ return (DECL_CONSTRUCTOR_P (fn)
+ && sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)));
+}
+
+// forked from gcc/cp/class.cc user_provided_p
+
+/* Returns true iff FN is a user-provided function, i.e. user-declared
+ and not defaulted at its first declaration. */
+
+bool
+user_provided_p (tree fn)
+{
+ return (!DECL_ARTIFICIAL (fn)
+ && !(DECL_INITIALIZED_IN_CLASS_P (fn)
+ && (DECL_DEFAULTED_FN (fn) || DECL_DELETED_FN (fn))));
+}
+
+// forked from gcc/cp/class.cc type_has_non_user_provided_default_constructor
+
+/* Returns true iff class T has a non-user-provided (i.e. implicitly
+ declared or explicitly defaulted in the class body) default
+ constructor. */
+
+bool
+type_has_non_user_provided_default_constructor (tree t)
+{
+ if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (t))
+ return false;
+ if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
+ return true;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ {
+ tree fn = *iter;
+ if (TREE_CODE (fn) == FUNCTION_DECL && default_ctor_p (fn)
+ && !user_provided_p (fn))
+ return true;
+ }
+
+ return false;
+}
+
+// forked from gcc/cp/class.cc default_init_uninitialized_part
+
+/* If default-initialization leaves part of TYPE uninitialized, returns
+ a DECL for the field or TYPE itself (DR 253). */
+
+tree
+default_init_uninitialized_part (tree type)
+{
+ tree t, r, binfo;
+ int i;
+
+ type = strip_array_types (type);
+ if (!CLASS_TYPE_P (type))
+ return type;
+ if (!type_has_non_user_provided_default_constructor (type))
+ return NULL_TREE;
+ for (binfo = TYPE_BINFO (type), i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
+ {
+ r = default_init_uninitialized_part (BINFO_TYPE (t));
+ if (r)
+ return r;
+ }
+ for (t = next_initializable_field (TYPE_FIELDS (type)); t;
+ t = next_initializable_field (DECL_CHAIN (t)))
+ if (!DECL_INITIAL (t) && !DECL_ARTIFICIAL (t))
+ {
+ r = default_init_uninitialized_part (TREE_TYPE (t));
+ if (r)
+ return DECL_P (r) ? r : t;
+ }
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/name-lookup.cc extract_conversion_operator
+
+/* FNS is an overload set of conversion functions. Return the
+ overloads converting to TYPE. */
+
+static tree
+extract_conversion_operator (tree fns, tree type)
+{
+ tree convs = NULL_TREE;
+ tree tpls = NULL_TREE;
+
+ for (ovl_iterator iter (fns); iter; ++iter)
+ {
+ if (same_type_p (DECL_CONV_FN_TYPE (*iter), type))
+ convs = lookup_add (*iter, convs);
+ }
+
+ if (!convs)
+ convs = tpls;
+
+ return convs;
+}
+
+// forked from gcc/cp/name-lookup.cc
+
+/* Look for NAME as an immediate member of KLASS (including
+ anon-members or unscoped enum member). TYPE_OR_FNS is zero for
+ regular search. >0 to get a type binding (if there is one) and <0
+ if you want (just) the member function binding.
+
+ Use this if you do not want lazy member creation. */
+
+tree
+get_class_binding_direct (tree klass, tree name, bool want_type)
+{
+ gcc_checking_assert (RECORD_OR_UNION_TYPE_P (klass));
+
+ /* Conversion operators can only be found by the marker conversion
+ operator name. */
+ bool conv_op = IDENTIFIER_CONV_OP_P (name);
+ tree lookup = conv_op ? conv_op_identifier : name;
+ tree val = NULL_TREE;
+ vec<tree, va_gc> *member_vec = CLASSTYPE_MEMBER_VEC (klass);
+
+ if (COMPLETE_TYPE_P (klass) && member_vec)
+ {
+ val = member_vec_binary_search (member_vec, lookup);
+ if (!val)
+ ;
+ else if (STAT_HACK_P (val))
+ val = want_type ? STAT_TYPE (val) : STAT_DECL (val);
+ else if (want_type && !DECL_DECLARES_TYPE_P (val))
+ val = NULL_TREE;
+ }
+ else
+ {
+ if (member_vec && !want_type)
+ val = member_vec_linear_search (member_vec, lookup);
+
+ if (!val || (TREE_CODE (val) == OVERLOAD && OVL_DEDUP_P (val)))
+ /* Dependent using declarations are a 'field', make sure we
+ return that even if we saw an overload already. */
+ if (tree field_val = fields_linear_search (klass, lookup, want_type))
+ {
+ if (!val)
+ val = field_val;
+ else if (TREE_CODE (field_val) == USING_DECL)
+ val = ovl_make (field_val, val);
+ }
+ }
+
+ /* Extract the conversion operators asked for, unless the general
+ conversion operator was requested. */
+ if (val && conv_op)
+ {
+ gcc_checking_assert (OVL_FUNCTION (val) == conv_op_marker);
+ val = OVL_CHAIN (val);
+ if (tree type = TREE_TYPE (name))
+ val = extract_conversion_operator (val, type);
+ }
+
+ return val;
+}
+
+#if defined ENABLE_TREE_CHECKING
+
+// forked from gcc/cp/tree.cc lang_check_failed
+
+/* 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", function,
+ trim_filename (file), line);
+}
+#endif /* ENABLE_TREE_CHECKING */
+
+// forked from gcc/cp/tree.cc skip_artificial_parms_for
+
+/* Given a FUNCTION_DECL FN and a chain LIST, skip as many elements of LIST
+ as there are artificial parms in FN. */
+
+tree
+skip_artificial_parms_for (const_tree fn, tree list)
+{
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+ list = TREE_CHAIN (list);
+ else
+ return list;
+
+ if (DECL_HAS_IN_CHARGE_PARM_P (fn))
+ list = TREE_CHAIN (list);
+ if (DECL_HAS_VTT_PARM_P (fn))
+ list = TREE_CHAIN (list);
+ return list;
+}
+
+// forked from gcc/cp/class.cc in_class_defaulted_default_constructor
+
+/* Returns the defaulted constructor if T has one. Otherwise, returns
+ NULL_TREE. */
+
+tree
+in_class_defaulted_default_constructor (tree t)
+{
+ if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+ return NULL_TREE;
+
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ {
+ tree fn = *iter;
+
+ if (DECL_DEFAULTED_IN_CLASS_P (fn) && default_ctor_p (fn))
+ return fn;
+ }
+
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/constexpr.cc
+
+/* Returns true iff FUN is an instantiation of a constexpr function
+ template or a defaulted constexpr function. */
+
+bool
+is_instantiation_of_constexpr (tree fun)
+{
+ return ((DECL_DEFAULTED_FN (fun) && DECL_DECLARED_CONSTEXPR_P (fun)));
+}
+
+// forked from gcc/cp/decl.cc check_for_uninitialized_const_var
+
+/* Issue an error message if DECL is an uninitialized const variable.
+ CONSTEXPR_CONTEXT_P is true when the function is called in a constexpr
+ context from potential_constant_expression. Returns true if all is well,
+ false otherwise. */
+
+bool
+check_for_uninitialized_const_var (tree decl, bool constexpr_context_p,
+ tsubst_flags_t complain)
+{
+ tree type = strip_array_types (TREE_TYPE (decl));
+
+ /* ``Unless explicitly declared extern, a const object does not have
+ external linkage and must be initialized. ($8.4; $12.1)'' ARM
+ 7.1.6 */
+ if (VAR_P (decl) && !TYPE_REF_P (type) && (RS_TYPE_CONST_P (type))
+ && !DECL_NONTRIVIALLY_INITIALIZED_P (decl))
+ {
+ tree field = default_init_uninitialized_part (type);
+ if (!field)
+ return true;
+
+ bool show_notes = true;
+
+ if (!constexpr_context_p)
+ {
+ if (RS_TYPE_CONST_P (type))
+ {
+ if (complain & tf_error)
+ show_notes = permerror (DECL_SOURCE_LOCATION (decl),
+ "uninitialized %<const %D%>", decl);
+ }
+ else
+ {
+ if (!is_instantiation_of_constexpr (current_function_decl)
+ && (complain & tf_error))
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "uninitialized variable %qD in %<constexpr%> "
+ "function",
+ decl);
+ else
+ show_notes = false;
+ }
+ }
+ else if (complain & tf_error)
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "uninitialized variable %qD in %<constexpr%> context", decl);
+
+ if (show_notes && CLASS_TYPE_P (type) && (complain & tf_error))
+ {
+ // tree defaulted_ctor;
+
+ // inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+ // "%q#T has no user-provided default constructor", type);
+ // defaulted_ctor = in_class_defaulted_default_constructor (type);
+ // if (defaulted_ctor)
+ // inform (DECL_SOURCE_LOCATION (defaulted_ctor),
+ // "constructor is not user-provided because it is "
+ // "explicitly defaulted in the class body");
+ // inform (DECL_SOURCE_LOCATION (field),
+ // "and the implicitly-defined constructor does not "
+ // "initialize %q#D",
+ // field);
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+// forked from gcc/cp/tree.cc cv_unqualified
+
+/* Return TYPE with const and volatile removed. */
+
+tree
+cv_unqualified (tree type)
+{
+ int quals;
+
+ if (type == error_mark_node)
+ return type;
+
+ quals = rs_type_quals (type);
+ quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
+ return rs_build_qualified_type (type, quals);
+}
+
+/* The C and C++ parsers both use vectors to hold function arguments.
+ For efficiency, we keep a cache of unused vectors. This is the
+ cache. */
+
+typedef vec<tree, va_gc> *tree_gc_vec;
+static GTY ((deletable)) vec<tree_gc_vec, va_gc> *tree_vector_cache;
+
+// forked from gcc/c-family/c-common.c make_tree_vector
+
+/* Return a new vector from the cache. If the cache is empty,
+ allocate a new vector. These vectors are GC'ed, so it is OK if the
+ pointer is not released.. */
+
+vec<tree, va_gc> *
+make_tree_vector (void)
+{
+ if (tree_vector_cache && !tree_vector_cache->is_empty ())
+ return tree_vector_cache->pop ();
+ else
+ {
+ /* Passing 0 to vec::alloc returns NULL, and our callers require
+ that we always return a non-NULL value. The vector code uses
+ 4 when growing a NULL vector, so we do too. */
+ vec<tree, va_gc> *v;
+ vec_alloc (v, 4);
+ return v;
+ }
+}
+
+// forked from gcc/c-family/c-common.c release_tree_vector
+
+/* Release a vector of trees back to the cache. */
+
+void
+release_tree_vector (vec<tree, va_gc> *vec)
+{
+ if (vec != NULL)
+ {
+ if (vec->allocated () >= 16)
+ /* Don't cache vecs that have expanded more than once. On a p64
+ target, vecs double in alloc size with each power of 2 elements, e.g
+ at 16 elements the alloc increases from 128 to 256 bytes. */
+ vec_free (vec);
+ else
+ {
+ vec->truncate (0);
+ vec_safe_push (tree_vector_cache, vec);
+ }
+ }
+}
+
+// forked from gcc/cp/cvt.cc instantiation_dependent_expression_p
+
+/* As above, but also check value-dependence of the expression as a whole. */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+ return false;
+}
+
+// forked from gcc/cp/cvt.cc cp_get_callee
+
+/* If CALL is a call, return the callee; otherwise null. */
+
+tree
+cp_get_callee (tree call)
+{
+ if (call == NULL_TREE)
+ return call;
+ else if (TREE_CODE (call) == CALL_EXPR)
+ return CALL_EXPR_FN (call);
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/typeck.cc build_nop
+
+/* Return a NOP_EXPR converting EXPR to TYPE. */
+
+tree
+build_nop (tree type, tree expr)
+{
+ if (type == error_mark_node || error_operand_p (expr))
+ return expr;
+ return build1_loc (EXPR_LOCATION (expr), NOP_EXPR, type, expr);
+}
+
+// forked from gcc/cp/tree.cc scalarish_type_p
+
+/* Returns 1 iff type T is something we want to treat as a scalar type for
+ the purpose of deciding whether it is trivial/POD/standard-layout. */
+
+bool
+scalarish_type_p (const_tree t)
+{
+ if (t == error_mark_node)
+ return 1;
+
+ return (SCALAR_TYPE_P (t) || VECTOR_TYPE_P (t));
+}
+
+// forked from gcc/cp/tree.cc type_has_nontrivial_copy_init
+
+/* Returns true iff copying an object of type T (including via move
+ constructor) is non-trivial. That is, T has no non-trivial copy
+ constructors and no non-trivial move constructors, and not all copy/move
+ constructors are deleted. This function implements the ABI notion of
+ non-trivial copy, which has diverged from the one in the standard. */
+
+bool
+type_has_nontrivial_copy_init (const_tree type)
+{
+ return false;
+}
+
+// forked from gcc/cp/tree.cc build_local_temp
+
+/* Return an undeclared local temporary of type TYPE for use in building a
+ TARGET_EXPR. */
+
+tree
+build_local_temp (tree type)
+{
+ tree slot = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+ DECL_ARTIFICIAL (slot) = 1;
+ DECL_IGNORED_P (slot) = 1;
+ DECL_CONTEXT (slot) = current_function_decl;
+ layout_decl (slot, 0);
+ return slot;
+}
+
+// forked from gcc/cp/lambda.cc is_normal_capture_proxy
+
+/* Returns true iff DECL is a capture proxy for a normal capture
+ (i.e. without explicit initializer). */
+
+bool
+is_normal_capture_proxy (tree decl)
+{
+ return false;
+}
+
+// forked from gcc/cp/c-common.cc reject_gcc_builtin
+
+/* For an EXPR of a FUNCTION_TYPE that references a GCC built-in function
+ with no library fallback or for an ADDR_EXPR whose operand is such type
+ issues an error pointing to the location LOC.
+ Returns true when the expression has been diagnosed and false
+ otherwise. */
+
+bool
+reject_gcc_builtin (const_tree expr, location_t loc /* = UNKNOWN_LOCATION */)
+{
+ if (TREE_CODE (expr) == ADDR_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ STRIP_ANY_LOCATION_WRAPPER (expr);
+
+ if (TREE_TYPE (expr) && TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
+ && TREE_CODE (expr) == FUNCTION_DECL
+ /* The intersection of DECL_BUILT_IN and DECL_IS_UNDECLARED_BUILTIN avoids
+ false positives for user-declared built-ins such as abs or
+ strlen, and for C++ operators new and delete.
+ The c_decl_implicit() test avoids false positives for implicitly
+ declared built-ins with library fallbacks (such as abs). */
+ && fndecl_built_in_p (expr) && DECL_IS_UNDECLARED_BUILTIN (expr)
+ && !DECL_ASSEMBLER_NAME_SET_P (expr))
+ {
+ if (loc == UNKNOWN_LOCATION)
+ loc = EXPR_LOC_OR_LOC (expr, input_location);
+
+ /* Reject arguments that are built-in functions with
+ no library fallback. */
+ error_at (loc, "built-in function %qE must be directly called", expr);
+
+ return true;
+ }
+
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc is_bitfield_expr_with_lowered_type
+
+/* If EXP is a reference to a bit-field, and the type of EXP does not
+ match the declared type of the bit-field, return the declared type
+ of the bit-field. Otherwise, return NULL_TREE. */
+
+tree
+is_bitfield_expr_with_lowered_type (const_tree exp)
+{
+ switch (TREE_CODE (exp))
+ {
+ case COND_EXPR:
+ if (!is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1)
+ ? TREE_OPERAND (exp, 1)
+ : TREE_OPERAND (exp, 0)))
+ return NULL_TREE;
+ return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 2));
+
+ case COMPOUND_EXPR:
+ return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 1));
+
+ case MODIFY_EXPR:
+ case SAVE_EXPR:
+ case UNARY_PLUS_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case NEGATE_EXPR:
+ case NON_LVALUE_EXPR:
+ case BIT_NOT_EXPR:
+ return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+
+ case COMPONENT_REF: {
+ tree field;
+
+ field = TREE_OPERAND (exp, 1);
+ if (TREE_CODE (field) != FIELD_DECL || !DECL_BIT_FIELD_TYPE (field))
+ return NULL_TREE;
+ if (same_type_ignoring_top_level_qualifiers_p (
+ TREE_TYPE (exp), DECL_BIT_FIELD_TYPE (field)))
+ return NULL_TREE;
+ return DECL_BIT_FIELD_TYPE (field);
+ }
+
+ case VAR_DECL:
+ if (DECL_HAS_VALUE_EXPR_P (exp))
+ return is_bitfield_expr_with_lowered_type (
+ DECL_VALUE_EXPR (CONST_CAST_TREE (exp)));
+ return NULL_TREE;
+
+ case VIEW_CONVERT_EXPR:
+ if (location_wrapper_p (exp))
+ return is_bitfield_expr_with_lowered_type (TREE_OPERAND (exp, 0));
+ else
+ return NULL_TREE;
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+// forked from gcc/cp/semantics.cc maybe_undo_parenthesized_ref
+
+/* If T is an id-expression obfuscated by force_paren_expr, undo the
+ obfuscation and return the underlying id-expression. Otherwise
+ return T. */
+
+tree
+maybe_undo_parenthesized_ref (tree t)
+{
+ if ((TREE_CODE (t) == PAREN_EXPR || TREE_CODE (t) == VIEW_CONVERT_EXPR)
+ && REF_PARENTHESIZED_P (t))
+ t = TREE_OPERAND (t, 0);
+
+ return t;
+}
+
+// forked from gcc/c-family/c-common.cc fold_offsetof
+
+/* Fold an offsetof-like expression. EXPR is a nested sequence of component
+ references with an INDIRECT_REF of a constant at the bottom; much like the
+ traditional rendering of offsetof as a macro. TYPE is the desired type of
+ the whole expression. Return the folded result. */
+
+tree
+fold_offsetof (tree expr, tree type, enum tree_code ctx)
+{
+ tree base, off, t;
+ tree_code code = TREE_CODE (expr);
+ switch (code)
+ {
+ case ERROR_MARK:
+ return expr;
+
+ case VAR_DECL:
+ error ("cannot apply %<offsetof%> to static data member %qD", expr);
+ return error_mark_node;
+
+ case CALL_EXPR:
+ case TARGET_EXPR:
+ error ("cannot apply %<offsetof%> when %<operator[]%> is overloaded");
+ return error_mark_node;
+
+ case NOP_EXPR:
+ case INDIRECT_REF:
+ if (!TREE_CONSTANT (TREE_OPERAND (expr, 0)))
+ {
+ error ("cannot apply %<offsetof%> to a non constant address");
+ return error_mark_node;
+ }
+ return convert (type, TREE_OPERAND (expr, 0));
+
+ case COMPONENT_REF:
+ base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ if (DECL_C_BIT_FIELD (t))
+ {
+ error ("attempt to take address of bit-field structure "
+ "member %qD",
+ t);
+ return error_mark_node;
+ }
+ off = size_binop_loc (input_location, PLUS_EXPR, DECL_FIELD_OFFSET (t),
+ size_int (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (t))
+ / BITS_PER_UNIT));
+ break;
+
+ case ARRAY_REF:
+ base = fold_offsetof (TREE_OPERAND (expr, 0), type, code);
+ if (base == error_mark_node)
+ return base;
+
+ t = TREE_OPERAND (expr, 1);
+ STRIP_ANY_LOCATION_WRAPPER (t);
+
+ /* Check if the offset goes beyond the upper bound of the array. */
+ if (TREE_CODE (t) == INTEGER_CST && tree_int_cst_sgn (t) >= 0)
+ {
+ tree upbound = array_ref_up_bound (expr);
+ if (upbound != NULL_TREE && TREE_CODE (upbound) == INTEGER_CST
+ && !tree_int_cst_equal (upbound,
+ TYPE_MAX_VALUE (TREE_TYPE (upbound))))
+ {
+ if (ctx != ARRAY_REF && ctx != COMPONENT_REF)
+ upbound = size_binop (PLUS_EXPR, upbound,
+ build_int_cst (TREE_TYPE (upbound), 1));
+ if (tree_int_cst_lt (upbound, t))
+ {
+ tree v;
+
+ for (v = TREE_OPERAND (expr, 0);
+ TREE_CODE (v) == COMPONENT_REF; v = TREE_OPERAND (v, 0))
+ if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+ == RECORD_TYPE)
+ {
+ tree fld_chain = DECL_CHAIN (TREE_OPERAND (v, 1));
+ for (; fld_chain; fld_chain = DECL_CHAIN (fld_chain))
+ if (TREE_CODE (fld_chain) == FIELD_DECL)
+ break;
+
+ if (fld_chain)
+ break;
+ }
+ /* Don't warn if the array might be considered a poor
+ man's flexible array member with a very permissive
+ definition thereof. */
+ if (TREE_CODE (v) == ARRAY_REF
+ || TREE_CODE (v) == COMPONENT_REF)
+ warning (OPT_Warray_bounds_,
+ "index %E denotes an offset "
+ "greater than size of %qT",
+ t, TREE_TYPE (TREE_OPERAND (expr, 0)));
+ }
+ }
+ }
+
+ t = convert (sizetype, t);
+ off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t);
+ break;
+
+ case COMPOUND_EXPR:
+ /* Handle static members of volatile structs. */
+ t = TREE_OPERAND (expr, 1);
+ gcc_checking_assert (VAR_P (get_base_address (t)));
+ return fold_offsetof (t, type);
+
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!POINTER_TYPE_P (type))
+ return size_binop (PLUS_EXPR, base, convert (type, off));
+ return fold_build_pointer_plus (base, off);
+}
+
+// forked from gcc/cp/tree.cc char_type_p
+
+/* Returns nonzero if TYPE is a character type, including wchar_t. */
+
+int
+char_type_p (tree type)
+{
+ 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));
+}
+
+// forked from gcc/cp/pt.cc resolve_nondeduced_context
+
+/* Core DR 115: In contexts where deduction is done and fails, or in
+ contexts where deduction is not done, if a template argument list is
+ specified and it, along with any default template arguments, identifies
+ a single function template specialization, then the template-id is an
+ lvalue for the function template specialization. */
+
+tree
+resolve_nondeduced_context (tree orig_expr, tsubst_flags_t complain)
+{
+ return orig_expr;
+}
+
+// forked from gcc/cp/pt.cc instantiate_non_dependent_or_null
+
+/* Like instantiate_non_dependent_expr, but return NULL_TREE rather than
+ an uninstantiated expression. */
+
+tree
+instantiate_non_dependent_or_null (tree expr)
+{
+ if (expr == NULL_TREE)
+ return NULL_TREE;
+
+ return expr;
+}
+
+// forked from gcc/cp/pt.cc resolve_nondeduced_context_or_error
+
+/* As above, but error out if the expression remains overloaded. */
+
+tree
+resolve_nondeduced_context_or_error (tree exp, tsubst_flags_t complain)
+{
+ exp = resolve_nondeduced_context (exp, complain);
+ if (type_unknown_p (exp))
+ {
+ if (complain & tf_error)
+ cxx_incomplete_type_error (exp, TREE_TYPE (exp));
+ return error_mark_node;
+ }
+ return exp;
+}
+
+// forked from gcc/cp/tree.cc really_overloaded_fn
+
+/* 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)
+{
+ return is_overloaded_fn (x) == 2;
+}
+
+// forked from gcc/cp/typeck..cc invalid_nonstatic_memfn_p
+
+/* EXPR is being used in a context that is not a function call.
+ Enforce:
+
+ [expr.ref]
+
+ The expression can be used only as the left-hand operand of a
+ member function call.
+
+ [expr.mptr.operator]
+
+ If the result of .* or ->* is a function, then that result can be
+ used only as the operand for the function call operator ().
+
+ by issuing an error message if appropriate. Returns true iff EXPR
+ violates these rules. */
+
+bool
+invalid_nonstatic_memfn_p (location_t loc, tree expr, tsubst_flags_t complain)
+{
+ if (expr == NULL_TREE)
+ return false;
+ /* Don't enforce this in MS mode. */
+ if (flag_ms_extensions)
+ return false;
+ if (is_overloaded_fn (expr) && !really_overloaded_fn (expr))
+ expr = get_first_fn (expr);
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (expr))
+ {
+ if (complain & tf_error)
+ {
+ if (DECL_P (expr))
+ {
+ error_at (loc, "invalid use of non-static member function %qD",
+ expr);
+ inform (DECL_SOURCE_LOCATION (expr), "declared here");
+ }
+ else
+ error_at (loc,
+ "invalid use of non-static member function of "
+ "type %qT",
+ TREE_TYPE (expr));
+ }
+ return true;
+ }
+ return false;
+}
+
+// forked from gcc/cp/call.cc strip_top_quals
+
+tree
+strip_top_quals (tree t)
+{
+ if (TREE_CODE (t) == ARRAY_TYPE)
+ return t;
+ return rs_build_qualified_type (t, 0);
+}
+
+// forked from gcc/cp/typeck2.cc cxx_incomplete_type_inform
+
+/* Print an inform about the declaration of the incomplete type TYPE. */
+
+// void
+// cxx_incomplete_type_inform (const_tree type)
+// {
+// if (!TYPE_MAIN_DECL (type))
+// return;
+
+// location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type));
+// tree ptype = strip_top_quals (CONST_CAST_TREE (type));
+
+// if (current_class_type && TYPE_BEING_DEFINED (current_class_type)
+// && same_type_p (ptype, current_class_type))
+// inform (loc,
+// "definition of %q#T is not complete until "
+// "the closing brace",
+// ptype);
+// else
+// inform (loc, "forward declaration of %q#T", ptype);
+// }
+
+// forked from gcc/cp/typeck2.cc cxx_incomplete_type_diagnostic
+
+/* Print an error message for invalid use of an incomplete type.
+ VALUE is the expression that was used (or 0 if that isn't known)
+ and TYPE is the type that was invalid. DIAG_KIND indicates the
+ type of diagnostic (see diagnostic.def). */
+
+void
+cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
+ const_tree type, diagnostic_t diag_kind)
+{
+ // bool is_decl = false, complained = false;
+
+ gcc_assert (diag_kind == DK_WARNING || diag_kind == DK_PEDWARN
+ || diag_kind == DK_ERROR);
+
+ /* Avoid duplicate error message. */
+ if (TREE_CODE (type) == ERROR_MARK)
+ return;
+
+ if (value)
+ {
+ STRIP_ANY_LOCATION_WRAPPER (value);
+
+ if (VAR_P (value) || TREE_CODE (value) == PARM_DECL
+ || TREE_CODE (value) == FIELD_DECL)
+ {
+ // complained = emit_diagnostic (diag_kind, DECL_SOURCE_LOCATION
+ // (value),
+ // 0, "%qD has incomplete type", value);
+ // is_decl = true;
+ }
+ }
+retry:
+ /* We must print an error message. Be clever about what it says. */
+
+ switch (TREE_CODE (type))
+ {
+ // case RECORD_TYPE:
+ // case UNION_TYPE:
+ // case ENUMERAL_TYPE:
+ // if (!is_decl)
+ // complained
+ // = emit_diagnostic (diag_kind, loc, 0,
+ // "invalid use of incomplete type %q#T", type);
+ // if (complained)
+ // cxx_incomplete_type_inform (type);
+ // break;
+
+ case VOID_TYPE:
+ emit_diagnostic (diag_kind, loc, 0, "invalid use of %qT", type);
+ break;
+
+ case ARRAY_TYPE:
+ if (TYPE_DOMAIN (type))
+ {
+ type = TREE_TYPE (type);
+ goto retry;
+ }
+ emit_diagnostic (diag_kind, loc, 0,
+ "invalid use of array with unspecified bounds");
+ break;
+
+ case OFFSET_TYPE:
+ bad_member : {
+ tree member = TREE_OPERAND (value, 1);
+ if (is_overloaded_fn (member))
+ member = get_first_fn (member);
+
+ if (DECL_FUNCTION_MEMBER_P (member) && !flag_ms_extensions)
+ {
+ gcc_rich_location richloc (loc);
+ /* If "member" has no arguments (other than "this"), then
+ add a fix-it hint. */
+ if (type_num_arguments (TREE_TYPE (member)) == 1)
+ richloc.add_fixit_insert_after ("()");
+ emit_diagnostic (diag_kind, &richloc, 0,
+ "invalid use of member function %qD "
+ "(did you forget the %<()%> ?)",
+ member);
+ }
+ else
+ emit_diagnostic (diag_kind, loc, 0,
+ "invalid use of member %qD "
+ "(did you forget the %<&%> ?)",
+ member);
+ }
+ break;
+
+ case LANG_TYPE:
+ if (type == init_list_type_node)
+ {
+ emit_diagnostic (diag_kind, loc, 0,
+ "invalid use of brace-enclosed initializer list");
+ break;
+ }
+ gcc_assert (type == unknown_type_node);
+ if (value && TREE_CODE (value) == COMPONENT_REF)
+ goto bad_member;
+ else if (value && TREE_CODE (value) == ADDR_EXPR)
+ emit_diagnostic (diag_kind, loc, 0,
+ "address of overloaded function with no contextual "
+ "type information");
+ else if (value && TREE_CODE (value) == OVERLOAD)
+ emit_diagnostic (
+ diag_kind, loc, 0,
+ "overloaded function with no contextual type information");
+ else
+ emit_diagnostic (
+ diag_kind, loc, 0,
+ "insufficient contextual information to determine type");
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+// forked from gcc/cp/decl2.cc decl_constant_var_p
+
+/* Nonzero for a VAR_DECL whose value can be used in a constant expression.
+
+ [expr.const]
+
+ An integral constant-expression can only involve ... const
+ variables of integral or enumeration types initialized with
+ constant expressions ...
+
+ C++0x also allows constexpr variables and temporaries initialized
+ with constant expressions. We handle the former here, but the latter
+ are just folded away in cxx_eval_constant_expression.
+
+ The standard does not require that the expression be non-volatile.
+ G++ implements the proposed correction in DR 457. */
+
+bool
+decl_constant_var_p (tree decl)
+{
+ if (!decl_maybe_constant_var_p (decl))
+ return false;
+
+ return DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl);
+}
+
+// forked from gcc/cp/decl.cc undeduced_auto_decl
+
+/* Returns true iff DECL is a variable or function declared with an auto type
+ that has not yet been deduced to a real type. */
+
+bool
+undeduced_auto_decl (tree decl)
+{
+ return false;
+}
+
+// forked from gcc/cp/decl.cc require_deduced_type
+
+/* Complain if DECL has an undeduced return type. */
+
+bool
+require_deduced_type (tree decl, tsubst_flags_t complain)
+{
+ return true;
+}
+
+/* Return the location of a tree passed to %+ formats. */
+
+location_t
+location_of (tree t)
+{
+ if (TYPE_P (t))
+ {
+ t = TYPE_MAIN_DECL (t);
+ if (t == NULL_TREE)
+ return input_location;
+ }
+ else if (TREE_CODE (t) == OVERLOAD)
+ t = OVL_FIRST (t);
+
+ if (DECL_P (t))
+ return DECL_SOURCE_LOCATION (t);
+
+ return EXPR_LOCATION (t);
+}
+
+/* For element type ELT_TYPE, return the appropriate type of the heap object
+ containing such element(s). COOKIE_SIZE is NULL or the size of cookie
+ in bytes. FULL_SIZE is NULL if it is unknown how big the heap allocation
+ will be, otherwise size of the heap object. If COOKIE_SIZE is NULL,
+ return array type ELT_TYPE[FULL_SIZE / sizeof(ELT_TYPE)], otherwise return
+ struct { size_t[COOKIE_SIZE/sizeof(size_t)]; ELT_TYPE[N]; }
+ where N is nothing (flexible array member) if FULL_SIZE is NULL, otherwise
+ it is computed such that the size of the struct fits into FULL_SIZE. */
+
+tree
+build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree full_size)
+{
+ gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size));
+ gcc_assert (full_size == NULL_TREE || tree_fits_uhwi_p (full_size));
+ unsigned HOST_WIDE_INT csz = cookie_size ? tree_to_uhwi (cookie_size) : 0;
+ tree itype2 = NULL_TREE;
+ if (full_size)
+ {
+ unsigned HOST_WIDE_INT fsz = tree_to_uhwi (full_size);
+ gcc_assert (fsz >= csz);
+ fsz -= csz;
+ fsz /= int_size_in_bytes (elt_type);
+ itype2 = build_index_type (size_int (fsz - 1));
+ if (!cookie_size)
+ return build_cplus_array_type (elt_type, itype2);
+ }
+ else
+ gcc_assert (cookie_size);
+ csz /= int_size_in_bytes (sizetype);
+ tree itype1 = build_index_type (size_int (csz - 1));
+ tree atype1 = build_cplus_array_type (sizetype, itype1);
+ tree atype2 = build_cplus_array_type (elt_type, itype2);
+ tree rtype = cxx_make_type (RECORD_TYPE);
+ TYPE_NAME (rtype) = heap_identifier;
+ tree fld1 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype1);
+ tree fld2 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype2);
+ DECL_FIELD_CONTEXT (fld1) = rtype;
+ DECL_FIELD_CONTEXT (fld2) = rtype;
+ DECL_ARTIFICIAL (fld1) = true;
+ DECL_ARTIFICIAL (fld2) = true;
+ TYPE_FIELDS (rtype) = fld1;
+ DECL_CHAIN (fld1) = fld2;
+ layout_type (rtype);
+ return rtype;
+}
+
+// forked from gcc/cp/class.cc field_poverlapping_p
+
+/* Return true iff FIELD_DECL DECL is potentially overlapping. */
+
+static bool
+field_poverlapping_p (tree decl)
+{
+ return lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (decl));
+}
+
+// forked from gcc/cp/class.cc is_empty_field
+
+/* Return true iff DECL is an empty field, either for an empty base or a
+ [[no_unique_address]] data member. */
+
+bool
+is_empty_field (tree decl)
+{
+ if (!decl || TREE_CODE (decl) != FIELD_DECL)
+ return false;
+
+ bool r = (is_empty_class (TREE_TYPE (decl)) && (field_poverlapping_p (decl)));
+
+ /* Empty fields should have size zero. */
+ gcc_checking_assert (!r || integer_zerop (DECL_SIZE (decl)));
+
+ return r;
+}
+
+// forked from gcc/cp/call.cc in_immediate_context
+
+/* Return true if in an immediate function context, or an unevaluated operand,
+ or a subexpression of an immediate invocation. */
+
+bool
+in_immediate_context ()
+{
+ return false;
+}
+
+// forked from gcc/cp/cvt.cc cp_get_fndecl_from_callee
+
+/* FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+ if we can. */
+
+tree
+rs_get_fndecl_from_callee (tree fn, bool fold /* = true */)
+{
+ if (fn == NULL_TREE)
+ return fn;
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ tree type = TREE_TYPE (fn);
+ if (type == NULL_TREE || !INDIRECT_TYPE_P (type))
+ return NULL_TREE;
+ if (fold)
+ fn = Compile::maybe_constant_init (fn);
+ STRIP_NOPS (fn);
+ if (TREE_CODE (fn) == ADDR_EXPR || TREE_CODE (fn) == FDESC_EXPR)
+ fn = TREE_OPERAND (fn, 0);
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ return fn;
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/cvt.cc cp_get_callee_fndecl_nofold
+tree
+rs_get_callee_fndecl_nofold (tree call)
+{
+ return rs_get_fndecl_from_callee (cp_get_callee (call), false);
+}
+
+// forked from gcc/cp/init.cc is_class_type
+
+/* Report an error if TYPE is not a user-defined, class type. If
+ OR_ELSE is nonzero, give an error message. */
+
+int
+is_class_type (tree type, int or_else)
+{
+ if (type == error_mark_node)
+ return 0;
+
+ if (!CLASS_TYPE_P (type))
+ {
+ if (or_else)
+ error ("%qT is not a class type", type);
+ return 0;
+ }
+ return 1;
+}
+
+// forked from gcc/cp/decl.cc lookup_enumerator
+
+/* Look for an enumerator with the given NAME within the enumeration
+ type ENUMTYPE. This routine is used primarily for qualified name
+ lookup into an enumerator in C++0x, e.g.,
+
+ enum class Color { Red, Green, Blue };
+
+ Color color = Color::Red;
+
+ Returns the value corresponding to the enumerator, or
+ NULL_TREE if no such enumerator was found. */
+tree
+lookup_enumerator (tree enumtype, tree name)
+{
+ tree e;
+ gcc_assert (enumtype && TREE_CODE (enumtype) == ENUMERAL_TYPE);
+
+ e = purpose_member (name, TYPE_VALUES (enumtype));
+ return e ? TREE_VALUE (e) : NULL_TREE;
+}
+
+// forked from gcc/cp/init.cc constant_value_1
+// commented out mark_used
+
+/* If DECL is a scalar enumeration constant or variable with a
+ constant initializer, return the initializer (or, its initializers,
+ recursively); otherwise, return DECL. If STRICT_P, the
+ initializer is only returned if DECL is a
+ constant-expression. If RETURN_AGGREGATE_CST_OK_P, it is ok to
+ return an aggregate constant. If UNSHARE_P, return an unshared
+ copy of the initializer. */
+
+static tree
+constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p,
+ bool unshare_p)
+{
+ while (TREE_CODE (decl) == CONST_DECL || decl_constant_var_p (decl)
+ || (!strict_p && VAR_P (decl)
+ && RS_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl))))
+ {
+ tree init;
+ /* If DECL is a static data member in a template
+ specialization, we must instantiate it here. The
+ initializer for the static data member is not processed
+ until needed; we need it now. */
+ // mark_used (decl, tf_none);
+ init = DECL_INITIAL (decl);
+ if (init == error_mark_node)
+ {
+ if (TREE_CODE (decl) == CONST_DECL
+ || DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ /* Treat the error as a constant to avoid cascading errors on
+ excessively recursive template instantiation (c++/9335). */
+ return init;
+ else
+ return decl;
+ }
+
+ /* Instantiate a non-dependent initializer for user variables. We
+ mustn't do this for the temporary for an array compound literal;
+ trying to instatiate the initializer will keep creating new
+ temporaries until we crash. Probably it's not useful to do it for
+ other artificial variables, either. */
+ if (!DECL_ARTIFICIAL (decl))
+ init = instantiate_non_dependent_or_null (init);
+ if (!init || !TREE_TYPE (init) || !TREE_CONSTANT (init)
+ || (!return_aggregate_cst_ok_p
+ /* Unless RETURN_AGGREGATE_CST_OK_P is true, do not
+ return an aggregate constant (of which string
+ literals are a special case), as we do not want
+ to make inadvertent copies of such entities, and
+ we must be sure that their addresses are the
+ same everywhere. */
+ && (TREE_CODE (init) == CONSTRUCTOR
+ || TREE_CODE (init) == STRING_CST)))
+ break;
+ /* Don't return a CONSTRUCTOR for a variable with partial run-time
+ initialization, since it doesn't represent the entire value.
+ Similarly for VECTOR_CSTs created by cp_folding those
+ CONSTRUCTORs. */
+ if ((TREE_CODE (init) == CONSTRUCTOR || TREE_CODE (init) == VECTOR_CST)
+ && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ break;
+ /* If the variable has a dynamic initializer, don't use its
+ DECL_INITIAL which doesn't reflect the real value. */
+ if (VAR_P (decl) && TREE_STATIC (decl)
+ && !DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
+ && DECL_NONTRIVIALLY_INITIALIZED_P (decl))
+ break;
+ decl = init;
+ }
+ return unshare_p ? unshare_expr (decl) : decl;
+}
+
+// forked from gcc/cp/init.cc decl_constant_value
+
+/* A more relaxed version of decl_really_constant_value, used by the
+ common C/C++ code. */
+
+tree
+decl_constant_value (tree decl, bool unshare_p)
+{
+ return constant_value_1 (decl, /*strict_p=*/false,
+ /*return_aggregate_cst_ok_p=*/true,
+ /*unshare_p=*/unshare_p);
+}
+
+// Below is forked from gcc/cp/init.cc decl_constant_value
+
+tree
+decl_constant_value (tree decl)
+{
+ return decl_constant_value (decl, /*unshare_p=*/true);
+}
+
+// Below is forked from gcc/cp/cp-gimplify.cc
+
+/* Type for source_location_table hash_set. */
+struct GTY ((for_user)) source_location_table_entry
+{
+ location_t loc;
+ unsigned uid;
+ tree var;
+};
+
+/* Traits class for function start hash maps below. */
+
+struct source_location_table_entry_hash
+ : ggc_remove<source_location_table_entry>
+{
+ typedef source_location_table_entry value_type;
+ typedef source_location_table_entry compare_type;
+
+ static hashval_t hash (const source_location_table_entry &ref)
+ {
+ inchash::hash hstate (0);
+ hstate.add_int (ref.loc);
+ hstate.add_int (ref.uid);
+ return hstate.end ();
+ }
+
+ static bool equal (const source_location_table_entry &ref1,
+ const source_location_table_entry &ref2)
+ {
+ return ref1.loc == ref2.loc && ref1.uid == ref2.uid;
+ }
+
+ static void mark_deleted (source_location_table_entry &ref)
+ {
+ ref.loc = UNKNOWN_LOCATION;
+ ref.uid = -1U;
+ ref.var = NULL_TREE;
+ }
+
+ static const bool empty_zero_p = true;
+
+ static void mark_empty (source_location_table_entry &ref)
+ {
+ ref.loc = UNKNOWN_LOCATION;
+ ref.uid = 0;
+ ref.var = NULL_TREE;
+ }
+
+ static bool is_deleted (const source_location_table_entry &ref)
+ {
+ return (ref.loc == UNKNOWN_LOCATION && ref.uid == -1U
+ && ref.var == NULL_TREE);
+ }
+
+ static bool is_empty (const source_location_table_entry &ref)
+ {
+ return (ref.loc == UNKNOWN_LOCATION && ref.uid == 0
+ && ref.var == NULL_TREE);
+ }
+
+ static void pch_nx (source_location_table_entry &p)
+ {
+ extern void gt_pch_nx (source_location_table_entry &);
+ gt_pch_nx (p);
+ }
+
+ static void pch_nx (source_location_table_entry &p, gt_pointer_operator op,
+ void *cookie)
+ {
+ extern void gt_pch_nx (source_location_table_entry *, gt_pointer_operator,
+ void *);
+ gt_pch_nx (&p, op, cookie);
+ }
+};
+
+static GTY (())
+ hash_table<source_location_table_entry_hash> *source_location_table;
+static GTY (()) unsigned int source_location_id;
+
+// Above is forked from gcc/cp/cp-gimplify.cc
+
+// forked from gcc/cp/tree.cc lvalue_kind
+
+/* If REF is an lvalue, returns the kind of lvalue that REF is.
+ Otherwise, returns clk_none. */
+
+cp_lvalue_kind
+lvalue_kind (const_tree ref)
+{
+ 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 (REFERENCE_REF_P (ref))
+ return lvalue_kind (TREE_OPERAND (ref, 0));
+
+ if (TREE_TYPE (ref) && TYPE_REF_P (TREE_TYPE (ref)))
+ {
+ /* unnamed rvalue references are rvalues */
+ if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref)) && TREE_CODE (ref) != PARM_DECL
+ && !VAR_P (ref)
+ && TREE_CODE (ref) != COMPONENT_REF
+ /* Functions are always lvalues. */
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (ref))) != FUNCTION_TYPE)
+ {
+ op1_lvalue_kind = clk_rvalueref;
+ if (implicit_rvalue_p (ref))
+ op1_lvalue_kind |= clk_implicit_rval;
+ return op1_lvalue_kind;
+ }
+
+ /* lvalue references and named rvalue references are lvalues. */
+ return clk_ordinary;
+ }
+
+ 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 PREDECREMENT_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 = clk_ordinary;
+ else
+ 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:
+ 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)
+ ;
+ else if (is_overloaded_fn (TREE_OPERAND (ref, 1)))
+ /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
+ situations. If we're seeing a COMPONENT_REF, it's a non-static
+ member, so it isn't an lvalue. */
+ op1_lvalue_kind = clk_none;
+ else if (TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL)
+ /* This can be IDENTIFIER_NODE in a template. */;
+ else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
+ {
+ /* Clear the ordinary bit. If this object was a class
+ rvalue we want to preserve that information. */
+ op1_lvalue_kind &= ~clk_ordinary;
+ /* The lvalue is for a bitfield. */
+ op1_lvalue_kind |= clk_bitfield;
+ }
+ else if (DECL_PACKED (TREE_OPERAND (ref, 1)))
+ op1_lvalue_kind |= clk_packed;
+
+ return op1_lvalue_kind;
+
+ case STRING_CST:
+ case COMPOUND_LITERAL_EXPR:
+ return clk_ordinary;
+
+ case CONST_DECL:
+ /* CONST_DECL without TREE_STATIC are enumeration values and
+ thus not lvalues. With TREE_STATIC they are used by ObjC++
+ in objc_build_string_object and need to be considered as
+ lvalues. */
+ if (!TREE_STATIC (ref))
+ return clk_none;
+ /* FALLTHRU */
+ case VAR_DECL:
+ if (VAR_P (ref) && DECL_HAS_VALUE_EXPR_P (ref))
+ return lvalue_kind (DECL_VALUE_EXPR (CONST_CAST_TREE (ref)));
+
+ if (TREE_READONLY (ref) && !TREE_STATIC (ref) && DECL_LANG_SPECIFIC (ref)
+ && DECL_IN_AGGR_P (ref))
+ return clk_none;
+ /* FALLTHRU */
+ case INDIRECT_REF:
+ case ARROW_EXPR:
+ case PARM_DECL:
+ case RESULT_DECL:
+ case PLACEHOLDER_EXPR:
+ return clk_ordinary;
+
+ case MAX_EXPR:
+ case MIN_EXPR:
+ /* Disallow <? and >? as lvalues if either argument side-effects. */
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 0))
+ || TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 1)))
+ return clk_none;
+ op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 0));
+ op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1));
+ break;
+
+ case COND_EXPR: {
+ 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 MODIFY_EXPR:
+ case TYPEID_EXPR:
+ return clk_ordinary;
+
+ case COMPOUND_EXPR:
+ return lvalue_kind (TREE_OPERAND (ref, 1));
+
+ case TARGET_EXPR:
+ return clk_class;
+
+ case VA_ARG_EXPR:
+ return (CLASS_TYPE_P (TREE_TYPE (ref)) ? clk_class : clk_none);
+
+ case CALL_EXPR:
+ /* We can see calls outside of TARGET_EXPR in templates. */
+ if (CLASS_TYPE_P (TREE_TYPE (ref)))
+ return clk_class;
+ return clk_none;
+
+ case FUNCTION_DECL:
+ /* All functions (except non-static-member functions) are
+ lvalues. */
+ return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref) ? clk_none : clk_ordinary);
+
+ 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:
+ if (!TREE_TYPE (ref))
+ return clk_none;
+ if (CLASS_TYPE_P (TREE_TYPE (ref))
+ || TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
+ return clk_class;
+ return clk_none;
+ }
+
+ /* If one operand is not an lvalue at all, then this expression is
+ not an lvalue. */
+ if (!op1_lvalue_kind || !op2_lvalue_kind)
+ return clk_none;
+
+ /* Otherwise, it's an lvalue, and it has all the odd properties
+ contributed by either operand. */
+ op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind;
+ /* It's not an ordinary lvalue if it involves any other kind. */
+ if ((op1_lvalue_kind & ~clk_ordinary) != clk_none)
+ op1_lvalue_kind &= ~clk_ordinary;
+ /* It can't be both a pseudo-lvalue and a non-addressable lvalue.
+ A COND_EXPR of those should be wrapped in a TARGET_EXPR. */
+ if ((op1_lvalue_kind & (clk_rvalueref | clk_class))
+ && (op1_lvalue_kind & (clk_bitfield | clk_packed)))
+ op1_lvalue_kind = clk_none;
+ return op1_lvalue_kind;
+}
+
+// forked from gcc/cp/tree.cc glvalue_p
+
+/* This differs from lvalue_p in that xvalues are included. */
+
+bool
+glvalue_p (const_tree ref)
+{
+ cp_lvalue_kind kind = lvalue_kind (ref);
+ if (kind & clk_class)
+ return false;
+ else
+ return (kind != clk_none);
+}
+
+// forked from gcc/cp/init.cc cv_qualified_p
+
+/* Returns nonzero if TYPE is const or volatile. */
+
+bool
+cv_qualified_p (const_tree type)
+{
+ int quals = rs_type_quals (type);
+ return (quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) != 0;
+}
+
+// forked from gcc/cp/tree.cc rvalue
+
+/* EXPR is being used in an rvalue context. Return a version of EXPR
+ that is marked as an rvalue. */
+
+tree
+rvalue (tree expr)
+{
+ tree type;
+
+ if (error_operand_p (expr))
+ return expr;
+
+ expr = mark_rvalue_use (expr);
+
+ /* [basic.lval]
+
+ Non-class rvalues always have cv-unqualified types. */
+ type = TREE_TYPE (expr);
+ if (!CLASS_TYPE_P (type) && cv_qualified_p (type))
+ type = cv_unqualified (type);
+
+ /* We need to do this for rvalue refs as well to get the right answer
+ from decltype; see c++/36628. */
+ if (glvalue_p (expr))
+ {
+ /* But don't use this function for class lvalues; use move (to treat an
+ lvalue as an xvalue) or force_rvalue (to make a prvalue copy). */
+ gcc_checking_assert (!CLASS_TYPE_P (type));
+ expr = build1 (NON_LVALUE_EXPR, type, expr);
+ }
+ else if (type != TREE_TYPE (expr))
+ expr = build_nop (type, expr);
+
+ return expr;
+}
+
+// forked from gcc/cp/tree.cc bitfield_p
+
+/* True if REF is a bit-field. */
+
+bool
+bitfield_p (const_tree ref)
+{
+ return (lvalue_kind (ref) & clk_bitfield);
+}
+
+// forked from gcc/cp/typeck.cc cxx_mark_addressable
+
+/* Mark EXP saying that we need to be able to take the
+ address of it; it should not be allocated in a register.
+ Value is true if successful. ARRAY_REF_P is true if this
+ is for ARRAY_REF construction - in that case we don't want
+ to look through VIEW_CONVERT_EXPR from VECTOR_TYPE to ARRAY_TYPE,
+ it is fine to use ARRAY_REFs for vector subscripts on vector
+ register variables.
+
+ C++: we do not allow `current_class_ptr' to be addressable. */
+
+bool
+cxx_mark_addressable (tree exp, bool array_ref_p)
+{
+ tree x = exp;
+
+ while (1)
+ switch (TREE_CODE (x))
+ {
+ case VIEW_CONVERT_EXPR:
+ if (array_ref_p && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+ && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))))
+ return true;
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case COMPONENT_REF:
+ if (bitfield_p (x))
+ error ("attempt to take address of bit-field");
+ /* FALLTHRU */
+ case ADDR_EXPR:
+ case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case PARM_DECL:
+ if (x == current_class_ptr)
+ {
+ error ("cannot take the address of %<this%>, which is an rvalue "
+ "expression");
+ TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later. */
+ return true;
+ }
+ /* Fall through. */
+
+ case VAR_DECL:
+ /* Caller should not be trying to mark initialized
+ constant fields addressable. */
+ gcc_assert (DECL_LANG_SPECIFIC (x) == 0 || DECL_IN_AGGR_P (x) == 0
+ || TREE_STATIC (x) || DECL_EXTERNAL (x));
+ /* Fall through. */
+
+ case RESULT_DECL:
+ if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) && !DECL_ARTIFICIAL (x))
+ {
+ if (VAR_P (x) && DECL_HARD_REGISTER (x))
+ {
+ error ("address of explicit register variable %qD requested",
+ x);
+ return false;
+ }
+ else if (extra_warnings)
+ warning (
+ OPT_Wextra,
+ "address requested for %qD, which is declared %<register%>", x);
+ }
+ TREE_ADDRESSABLE (x) = 1;
+ return true;
+
+ case CONST_DECL:
+ case FUNCTION_DECL:
+ TREE_ADDRESSABLE (x) = 1;
+ return true;
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return true;
+
+ case TARGET_EXPR:
+ TREE_ADDRESSABLE (x) = 1;
+ cxx_mark_addressable (TREE_OPERAND (x, 0));
+ return true;
+
+ default:
+ return true;
+ }
+}
+
+// forked from gcc/cp/typeck.cc build_address
+
+/* Returns the address of T. This function will fold away
+ ADDR_EXPR of INDIRECT_REF. This is only for low-level usage;
+ most places should use cp_build_addr_expr instead. */
+
+tree
+build_address (tree t)
+{
+ if (error_operand_p (t) || !cxx_mark_addressable (t))
+ return error_mark_node;
+ gcc_checking_assert (TREE_CODE (t) != CONSTRUCTOR);
+ t = build_fold_addr_expr_loc (EXPR_LOCATION (t), t);
+ if (TREE_CODE (t) != ADDR_EXPR)
+ t = rvalue (t);
+ return t;
+}
+
+// forked from gcc/cp/gp-gimplify.cc fold_builtin_source_location
+
+/* Fold __builtin_source_location () call. LOC is the location
+ of the call. */
+
+tree
+fold_builtin_source_location (location_t loc)
+{
+ // if (source_location_impl == NULL_TREE)
+ // {
+ // auto_diagnostic_group d;
+ // source_location_impl = get_source_location_impl_type (loc);
+ // if (source_location_impl == error_mark_node)
+ // inform (loc, "evaluating %qs", "__builtin_source_location");
+ // }
+ if (source_location_impl == error_mark_node)
+ return build_zero_cst (const_ptr_type_node);
+ if (source_location_table == NULL)
+ source_location_table
+ = hash_table<source_location_table_entry_hash>::create_ggc (64);
+ const line_map_ordinary *map;
+ source_location_table_entry entry;
+ entry.loc = linemap_resolve_location (line_table, loc,
+ LRK_MACRO_EXPANSION_POINT, &map);
+ entry.uid = current_function_decl ? DECL_UID (current_function_decl) : -1;
+ entry.var = error_mark_node;
+ source_location_table_entry *entryp
+ = source_location_table->find_slot (entry, INSERT);
+ tree var;
+ if (entryp->var)
+ var = entryp->var;
+ else
+ {
+ char tmp_name[32];
+ ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lsrc_loc", source_location_id++);
+ var = build_decl (loc, VAR_DECL, get_identifier (tmp_name),
+ source_location_impl);
+ TREE_STATIC (var) = 1;
+ TREE_PUBLIC (var) = 0;
+ DECL_ARTIFICIAL (var) = 1;
+ DECL_IGNORED_P (var) = 1;
+ DECL_EXTERNAL (var) = 0;
+ DECL_DECLARED_CONSTEXPR_P (var) = 1;
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (var) = 1;
+ layout_decl (var, 0);
+
+ vec<constructor_elt, va_gc> *v = NULL;
+ vec_alloc (v, 4);
+ for (tree field = TYPE_FIELDS (source_location_impl);
+ (field = next_initializable_field (field)) != NULL_TREE;
+ field = DECL_CHAIN (field))
+ {
+ const char *n = IDENTIFIER_POINTER (DECL_NAME (field));
+ tree val = NULL_TREE;
+ if (strcmp (n, "_M_file_name") == 0)
+ {
+ if (const char *fname = LOCATION_FILE (loc))
+ {
+ fname = remap_macro_filename (fname);
+ val = build_string_literal (strlen (fname) + 1, fname);
+ }
+ else
+ val = build_string_literal (1, "");
+ }
+ else if (strcmp (n, "_M_function_name") == 0)
+ {
+ const char *name = "todo: add funciton name here";
+
+ // if (current_function_decl)
+ // name = cxx_printable_name (current_function_decl, 2);
+
+ val = build_string_literal (strlen (name) + 1, name);
+ }
+ else if (strcmp (n, "_M_line") == 0)
+ val = build_int_cst (TREE_TYPE (field), LOCATION_LINE (loc));
+ else if (strcmp (n, "_M_column") == 0)
+ val = build_int_cst (TREE_TYPE (field), LOCATION_COLUMN (loc));
+ else
+ gcc_unreachable ();
+ CONSTRUCTOR_APPEND_ELT (v, field, val);
+ }
+
+ tree ctor = build_constructor (source_location_impl, v);
+ TREE_CONSTANT (ctor) = 1;
+ TREE_STATIC (ctor) = 1;
+ DECL_INITIAL (var) = ctor;
+ varpool_node::finalize_decl (var);
+ *entryp = entry;
+ entryp->var = var;
+ }
+
+ return build_fold_addr_expr_with_type_loc (loc, var, const_ptr_type_node);
+}
+
+// forked from gcc/c-family/c-common.cc braced_lists_to_strings
+
+/* Attempt to convert a braced array initializer list CTOR for array
+ TYPE into a STRING_CST for convenience and efficiency. Return
+ the converted string on success or the original ctor on failure. */
+
+static tree
+braced_list_to_string (tree type, tree ctor, bool member)
+{
+ /* Ignore non-members with unknown size like arrays with unspecified
+ bound. */
+ tree typesize = TYPE_SIZE_UNIT (type);
+ if (!member && !tree_fits_uhwi_p (typesize))
+ return ctor;
+
+ /* If the target char size differes from the host char size, we'd risk
+ loosing data and getting object sizes wrong by converting to
+ host chars. */
+ if (TYPE_PRECISION (char_type_node) != CHAR_BIT)
+ return ctor;
+
+ /* If the array has an explicit bound, use it to constrain the size
+ of the string. If it doesn't, be sure to create a string that's
+ as long as implied by the index of the last zero specified via
+ a designator, as in:
+ const char a[] = { [7] = 0 }; */
+ unsigned HOST_WIDE_INT maxelts;
+ if (typesize)
+ {
+ maxelts = tree_to_uhwi (typesize);
+ maxelts /= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (type)));
+ }
+ else
+ maxelts = HOST_WIDE_INT_M1U;
+
+ /* Avoid converting initializers for zero-length arrays (but do
+ create them for flexible array members). */
+ if (!maxelts)
+ return ctor;
+
+ unsigned HOST_WIDE_INT nelts = CONSTRUCTOR_NELTS (ctor);
+
+ auto_vec<char> str;
+ str.reserve (nelts + 1);
+
+ unsigned HOST_WIDE_INT i;
+ tree index, value;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), i, index, value)
+ {
+ unsigned HOST_WIDE_INT idx = i;
+ if (index)
+ {
+ if (!tree_fits_uhwi_p (index))
+ return ctor;
+ idx = tree_to_uhwi (index);
+ }
+
+ /* auto_vec is limited to UINT_MAX elements. */
+ if (idx > UINT_MAX)
+ return ctor;
+
+ /* Avoid non-constant initializers. */
+ if (!tree_fits_shwi_p (value))
+ return ctor;
+
+ /* Skip over embedded nuls except the last one (initializer
+ elements are in ascending order of indices). */
+ HOST_WIDE_INT val = tree_to_shwi (value);
+ if (!val && i + 1 < nelts)
+ continue;
+
+ if (idx < str.length ())
+ return ctor;
+
+ /* Bail if the CTOR has a block of more than 256 embedded nuls
+ due to implicitly initialized elements. */
+ unsigned nchars = (idx - str.length ()) + 1;
+ if (nchars > 256)
+ return ctor;
+
+ if (nchars > 1)
+ {
+ str.reserve (idx);
+ str.quick_grow_cleared (idx);
+ }
+
+ if (idx >= maxelts)
+ return ctor;
+
+ str.safe_insert (idx, val);
+ }
+
+ /* Append a nul string termination. */
+ if (maxelts != HOST_WIDE_INT_M1U && str.length () < maxelts)
+ str.safe_push (0);
+
+ /* Build a STRING_CST with the same type as the array. */
+ tree res = build_string (str.length (), str.begin ());
+ TREE_TYPE (res) = type;
+ return res;
+}
+
+// forked from gcc/c-family/c-common.cc braced_lists_to_strings
+
+/* Implementation of the two-argument braced_lists_to_string withe
+ the same arguments plus MEMBER which is set for struct members
+ to allow initializers for flexible member arrays. */
+
+static tree
+braced_lists_to_strings (tree type, tree ctor, bool member)
+{
+ if (TREE_CODE (ctor) != CONSTRUCTOR)
+ return ctor;
+
+ tree_code code = TREE_CODE (type);
+
+ tree ttp;
+ if (code == ARRAY_TYPE)
+ ttp = TREE_TYPE (type);
+ else if (code == RECORD_TYPE)
+ {
+ ttp = TREE_TYPE (ctor);
+ if (TREE_CODE (ttp) == ARRAY_TYPE)
+ {
+ type = ttp;
+ ttp = TREE_TYPE (ttp);
+ }
+ }
+ else
+ return ctor;
+
+ if ((TREE_CODE (ttp) == ARRAY_TYPE || TREE_CODE (ttp) == INTEGER_TYPE)
+ && TYPE_STRING_FLAG (ttp))
+ return braced_list_to_string (type, ctor, member);
+
+ code = TREE_CODE (ttp);
+ if (code == ARRAY_TYPE || RECORD_OR_UNION_TYPE_P (ttp))
+ {
+ bool rec = RECORD_OR_UNION_TYPE_P (ttp);
+
+ /* Handle array of arrays or struct member initializers. */
+ tree val;
+ unsigned HOST_WIDE_INT idx;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
+ {
+ val = braced_lists_to_strings (ttp, val, rec);
+ CONSTRUCTOR_ELT (ctor, idx)->value = val;
+ }
+ }
+
+ return ctor;
+}
+
+// forked from gcc/c-family/c-common.cc braced_lists_to_strings
+
+/* Attempt to convert a CTOR containing braced array initializer lists
+ for array TYPE into one containing STRING_CSTs, for convenience and
+ efficiency. Recurse for arrays of arrays and member initializers.
+ Return the converted CTOR or STRING_CST on success or the original
+ CTOR otherwise. */
+
+tree
+braced_lists_to_strings (tree type, tree ctor)
+{
+ return braced_lists_to_strings (type, ctor, false);
+}
+
+/*---------------------------------------------------------------------------
+ Constraint satisfaction
+---------------------------------------------------------------------------*/
+
+// forked from gcc/cp/constraint.cc satisfying_constraint
+
+/* True if we are currently satisfying a failed_type_completions. */
+
+static bool satisfying_constraint;
+
+// forked from gcc/cp/constraint.cc satisfying_constraint
+
+/* A vector of incomplete types (and of declarations with undeduced return
+ type), appended to by note_failed_type_completion_for_satisfaction. The
+ satisfaction caches use this in order to keep track of "potentially unstable"
+ satisfaction results.
+
+ Since references to entries in this vector are stored only in the
+ GC-deletable sat_cache, it's safe to make this deletable as well. */
+
+static GTY ((deletable)) vec<tree, va_gc> *failed_type_completions;
+
+// forked from gcc/cp/constraint.cc note_failed_type_completion_for_satisfaction
+
+/* Called whenever a type completion (or return type deduction) failure occurs
+ that definitely affects the meaning of the program, by e.g. inducing
+ substitution failure. */
+
+void
+note_failed_type_completion_for_satisfaction (tree t)
+{
+ if (satisfying_constraint)
+ {
+ gcc_checking_assert ((TYPE_P (t) && !COMPLETE_TYPE_P (t))
+ || (DECL_P (t) && undeduced_auto_decl (t)));
+ vec_safe_push (failed_type_completions, t);
+ }
+}
+
+// forked from gcc/cp/typeck.cc complete_type
+
+/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
+ a template instantiation, do the instantiation. Returns TYPE,
+ whether or not it could be completed, unless something goes
+ horribly wrong, in which case the error_mark_node is returned. */
+
+tree
+complete_type (tree type)
+{
+ if (type == NULL_TREE)
+ /* Rather than crash, we return something sure to cause an error
+ at some point. */
+ return error_mark_node;
+
+ if (type == error_mark_node || COMPLETE_TYPE_P (type))
+ ;
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree t = complete_type (TREE_TYPE (type));
+ unsigned int needs_constructing, has_nontrivial_dtor;
+ if (COMPLETE_TYPE_P (t))
+ layout_type (type);
+ needs_constructing = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+ has_nontrivial_dtor
+ = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+ {
+ TYPE_NEEDS_CONSTRUCTING (t) = needs_constructing;
+ TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = has_nontrivial_dtor;
+ }
+ }
+
+ return type;
+}
+
+// forked from gcc/cp/typeck.cc complete_type_or_maybe_complain
+
+/* Like complete_type, but issue an error if the TYPE cannot be completed.
+ VALUE is used for informative diagnostics.
+ Returns NULL_TREE if the type cannot be made complete. */
+
+tree
+complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
+{
+ type = complete_type (type);
+ if (type == error_mark_node)
+ /* We already issued an error. */
+ return NULL_TREE;
+ else if (!COMPLETE_TYPE_P (type))
+ {
+ if (complain & tf_error)
+ cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ note_failed_type_completion_for_satisfaction (type);
+ return NULL_TREE;
+ }
+ else
+ return type;
+}
+
+// forked from gcc/cp/typeck.cc complete_type_or_else
+
+tree
+complete_type_or_else (tree type, tree value)
+{
+ return complete_type_or_maybe_complain (type, value, tf_warning_or_error);
+}
+
+// forked from gcc/cp/tree.cc std_layout_type_p
+
+/* Returns true iff T is a standard-layout type, as defined in
+ [basic.types]. */
+
+bool
+std_layout_type_p (const_tree t)
+{
+ t = strip_array_types (CONST_CAST_TREE (t));
+
+ if (CLASS_TYPE_P (t))
+ return !CLASSTYPE_NON_STD_LAYOUT (t);
+ else
+ return scalarish_type_p (t);
+}
+
+// forked from /gcc/cp/semantics.cc first_nonstatic_data_member_p
+
+/* Helper function for fold_builtin_is_pointer_inverconvertible_with_class,
+ return true if MEMBERTYPE is the type of the first non-static data member
+ of TYPE or for unions of any members. */
+static bool
+first_nonstatic_data_member_p (tree type, tree membertype)
+{
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ {
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ if (DECL_FIELD_IS_BASE (field) && is_empty_field (field))
+ continue;
+ if (DECL_FIELD_IS_BASE (field))
+ return first_nonstatic_data_member_p (TREE_TYPE (field), membertype);
+ if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ {
+ if ((TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
+ || std_layout_type_p (TREE_TYPE (field)))
+ && first_nonstatic_data_member_p (TREE_TYPE (field), membertype))
+ return true;
+ }
+ else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field),
+ membertype))
+ return true;
+ if (TREE_CODE (type) != UNION_TYPE)
+ return false;
+ }
+ return false;
+}
+
+// forked from gcc/cp/semantics.cc
+// fold_builtin_is_pointer_inverconvertible_with_class
+
+/* Fold __builtin_is_pointer_interconvertible_with_class call. */
+
+tree
+fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs,
+ tree *args)
+{
+ /* Unless users call the builtin directly, the following 3 checks should be
+ ensured from std::is_pointer_interconvertible_with_class function
+ template. */
+ if (nargs != 1)
+ {
+ error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> "
+ "needs a single argument");
+ return boolean_false_node;
+ }
+ tree arg = args[0];
+ if (error_operand_p (arg))
+ return boolean_false_node;
+ if (!TYPE_PTRMEM_P (TREE_TYPE (arg)))
+ {
+ error_at (loc, "%<__builtin_is_pointer_interconvertible_with_class%> "
+ "argument is not pointer to member");
+ return boolean_false_node;
+ }
+
+ if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg)))
+ return boolean_false_node;
+
+ tree membertype = TREE_TYPE (TREE_TYPE (arg));
+ tree basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg));
+ if (!complete_type_or_else (basetype, NULL_TREE))
+ return boolean_false_node;
+
+ if (TREE_CODE (basetype) != UNION_TYPE && !std_layout_type_p (basetype))
+ return boolean_false_node;
+
+ if (!first_nonstatic_data_member_p (basetype, membertype))
+ return boolean_false_node;
+
+ if (integer_nonzerop (arg))
+ return boolean_false_node;
+ if (integer_zerop (arg))
+ return boolean_true_node;
+
+ return fold_build2 (EQ_EXPR, boolean_type_node, arg,
+ build_zero_cst (TREE_TYPE (arg)));
+}
+
+// forked from gcc/c-family/c-common.cc registered_builtin_types
+
+/* Used for communication between c_common_type_for_mode and
+ c_register_builtin_type. */
+tree registered_builtin_types;
+
+/* Return a data type that has machine mode MODE.
+ If the mode is an integer,
+ then UNSIGNEDP selects between signed and unsigned types.
+ If the mode is a fixed-point mode,
+ then UNSIGNEDP selects between saturating and nonsaturating types. */
+
+// forked from gcc/c-family/c-common.cc c_common_type_for_mode
+
+tree
+c_common_type_for_mode (machine_mode mode, int unsignedp)
+{
+ tree t;
+ int i;
+
+ if (mode == TYPE_MODE (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (mode == TYPE_MODE (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (mode == TYPE_MODE (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (mode == TYPE_MODE (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (mode == TYPE_MODE (long_long_integer_type_node))
+ return unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node;
+
+ for (i = 0; i < NUM_INT_N_ENTS; i++)
+ if (int_n_enabled_p[i] && mode == int_n_data[i].m)
+ return (unsignedp ? int_n_trees[i].unsigned_type
+ : int_n_trees[i].signed_type);
+
+ if (mode == QImode)
+ return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
+ if (mode == HImode)
+ return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+
+ if (mode == SImode)
+ return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+
+ if (mode == DImode)
+ return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+ if (mode == TYPE_MODE (intTI_type_node))
+ return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+#endif
+
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+
+ if (mode == TYPE_MODE (long_double_type_node))
+ return long_double_type_node;
+
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+ && mode == TYPE_MODE (FLOATN_NX_TYPE_NODE (i)))
+ return FLOATN_NX_TYPE_NODE (i);
+
+ if (mode == TYPE_MODE (void_type_node))
+ return void_type_node;
+
+ if (mode == TYPE_MODE (build_pointer_type (char_type_node))
+ || mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+ {
+ unsigned int precision
+ = GET_MODE_PRECISION (as_a<scalar_int_mode> (mode));
+ return (unsignedp ? make_unsigned_type (precision)
+ : make_signed_type (precision));
+ }
+
+ if (COMPLEX_MODE_P (mode))
+ {
+ machine_mode inner_mode;
+ tree inner_type;
+
+ if (mode == TYPE_MODE (complex_float_type_node))
+ return complex_float_type_node;
+ if (mode == TYPE_MODE (complex_double_type_node))
+ return complex_double_type_node;
+ if (mode == TYPE_MODE (complex_long_double_type_node))
+ return complex_long_double_type_node;
+
+ for (i = 0; i < NUM_FLOATN_NX_TYPES; i++)
+ if (COMPLEX_FLOATN_NX_TYPE_NODE (i) != NULL_TREE
+ && mode == TYPE_MODE (COMPLEX_FLOATN_NX_TYPE_NODE (i)))
+ return COMPLEX_FLOATN_NX_TYPE_NODE (i);
+
+ if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+ return complex_integer_type_node;
+
+ inner_mode = GET_MODE_INNER (mode);
+ inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_complex_type (inner_type);
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL
+ && valid_vector_subparts_p (GET_MODE_NUNITS (mode)))
+ {
+ unsigned int elem_bits
+ = vector_element_size (GET_MODE_BITSIZE (mode), GET_MODE_NUNITS (mode));
+ tree bool_type = build_nonstandard_boolean_type (elem_bits);
+ return build_vector_type_for_mode (bool_type, mode);
+ }
+ else if (VECTOR_MODE_P (mode)
+ && valid_vector_subparts_p (GET_MODE_NUNITS (mode)))
+ {
+ machine_mode inner_mode = GET_MODE_INNER (mode);
+ tree inner_type = c_common_type_for_mode (inner_mode, unsignedp);
+ if (inner_type != NULL_TREE)
+ return build_vector_type_for_mode (inner_type, mode);
+ }
+
+ if (dfloat32_type_node != NULL_TREE && mode == TYPE_MODE (dfloat32_type_node))
+ return dfloat32_type_node;
+ if (dfloat64_type_node != NULL_TREE && mode == TYPE_MODE (dfloat64_type_node))
+ return dfloat64_type_node;
+ if (dfloat128_type_node != NULL_TREE
+ && mode == TYPE_MODE (dfloat128_type_node))
+ return dfloat128_type_node;
+
+ if (ALL_SCALAR_FIXED_POINT_MODE_P (mode))
+ {
+ if (mode == TYPE_MODE (short_fract_type_node))
+ return unsignedp ? sat_short_fract_type_node : short_fract_type_node;
+ if (mode == TYPE_MODE (fract_type_node))
+ return unsignedp ? sat_fract_type_node : fract_type_node;
+ if (mode == TYPE_MODE (long_fract_type_node))
+ return unsignedp ? sat_long_fract_type_node : long_fract_type_node;
+ if (mode == TYPE_MODE (long_long_fract_type_node))
+ return unsignedp ? sat_long_long_fract_type_node
+ : long_long_fract_type_node;
+
+ if (mode == TYPE_MODE (unsigned_short_fract_type_node))
+ return unsignedp ? sat_unsigned_short_fract_type_node
+ : unsigned_short_fract_type_node;
+ if (mode == TYPE_MODE (unsigned_fract_type_node))
+ return unsignedp ? sat_unsigned_fract_type_node
+ : unsigned_fract_type_node;
+ if (mode == TYPE_MODE (unsigned_long_fract_type_node))
+ return unsignedp ? sat_unsigned_long_fract_type_node
+ : unsigned_long_fract_type_node;
+ if (mode == TYPE_MODE (unsigned_long_long_fract_type_node))
+ return unsignedp ? sat_unsigned_long_long_fract_type_node
+ : unsigned_long_long_fract_type_node;
+
+ if (mode == TYPE_MODE (short_accum_type_node))
+ return unsignedp ? sat_short_accum_type_node : short_accum_type_node;
+ if (mode == TYPE_MODE (accum_type_node))
+ return unsignedp ? sat_accum_type_node : accum_type_node;
+ if (mode == TYPE_MODE (long_accum_type_node))
+ return unsignedp ? sat_long_accum_type_node : long_accum_type_node;
+ if (mode == TYPE_MODE (long_long_accum_type_node))
+ return unsignedp ? sat_long_long_accum_type_node
+ : long_long_accum_type_node;
+
+ if (mode == TYPE_MODE (unsigned_short_accum_type_node))
+ return unsignedp ? sat_unsigned_short_accum_type_node
+ : unsigned_short_accum_type_node;
+ if (mode == TYPE_MODE (unsigned_accum_type_node))
+ return unsignedp ? sat_unsigned_accum_type_node
+ : unsigned_accum_type_node;
+ if (mode == TYPE_MODE (unsigned_long_accum_type_node))
+ return unsignedp ? sat_unsigned_long_accum_type_node
+ : unsigned_long_accum_type_node;
+ if (mode == TYPE_MODE (unsigned_long_long_accum_type_node))
+ return unsignedp ? sat_unsigned_long_long_accum_type_node
+ : unsigned_long_long_accum_type_node;
+
+ if (mode == QQmode)
+ return unsignedp ? sat_qq_type_node : qq_type_node;
+ if (mode == HQmode)
+ return unsignedp ? sat_hq_type_node : hq_type_node;
+ if (mode == SQmode)
+ return unsignedp ? sat_sq_type_node : sq_type_node;
+ if (mode == DQmode)
+ return unsignedp ? sat_dq_type_node : dq_type_node;
+ if (mode == TQmode)
+ return unsignedp ? sat_tq_type_node : tq_type_node;
+
+ if (mode == UQQmode)
+ return unsignedp ? sat_uqq_type_node : uqq_type_node;
+ if (mode == UHQmode)
+ return unsignedp ? sat_uhq_type_node : uhq_type_node;
+ if (mode == USQmode)
+ return unsignedp ? sat_usq_type_node : usq_type_node;
+ if (mode == UDQmode)
+ return unsignedp ? sat_udq_type_node : udq_type_node;
+ if (mode == UTQmode)
+ return unsignedp ? sat_utq_type_node : utq_type_node;
+
+ if (mode == HAmode)
+ return unsignedp ? sat_ha_type_node : ha_type_node;
+ if (mode == SAmode)
+ return unsignedp ? sat_sa_type_node : sa_type_node;
+ if (mode == DAmode)
+ return unsignedp ? sat_da_type_node : da_type_node;
+ if (mode == TAmode)
+ return unsignedp ? sat_ta_type_node : ta_type_node;
+
+ if (mode == UHAmode)
+ return unsignedp ? sat_uha_type_node : uha_type_node;
+ if (mode == USAmode)
+ return unsignedp ? sat_usa_type_node : usa_type_node;
+ if (mode == UDAmode)
+ return unsignedp ? sat_uda_type_node : uda_type_node;
+ if (mode == UTAmode)
+ return unsignedp ? sat_uta_type_node : uta_type_node;
+ }
+
+ for (t = registered_builtin_types; t; t = TREE_CHAIN (t))
+ {
+ tree type = TREE_VALUE (t);
+ if (TYPE_MODE (type) == mode
+ && VECTOR_TYPE_P (type) == VECTOR_MODE_P (mode)
+ && !!unsignedp == !!TYPE_UNSIGNED (type))
+ return type;
+ }
+ return NULL_TREE;
+}
+
+// forked from gcc/cp/semantics.cc finish_underlying_type
+
+/* Implement the __underlying_type keyword: Return the underlying
+ type of TYPE, suitable for use as a type-specifier. */
+
+tree
+finish_underlying_type (tree type)
+{
+ tree underlying_type;
+
+ if (!complete_type_or_else (type, NULL_TREE))
+ return error_mark_node;
+
+ if (TREE_CODE (type) != ENUMERAL_TYPE)
+ {
+ error ("%qT is not an enumeration type", type);
+ return error_mark_node;
+ }
+
+ underlying_type = ENUM_UNDERLYING_TYPE (type);
+
+ /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE
+ includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information.
+ See finish_enum_value_list for details. */
+ if (!ENUM_FIXED_UNDERLYING_TYPE_P (type))
+ underlying_type = c_common_type_for_mode (TYPE_MODE (underlying_type),
+ TYPE_UNSIGNED (underlying_type));
+
+ return underlying_type;
+}
+
+// forked from gcc/cp/typeck.cc layout_compatible_type_p
+
+/* Return true if TYPE1 and TYPE2 are layout-compatible types. */
+
+bool
+layout_compatible_type_p (tree type1, tree type2)
+{
+ if (type1 == error_mark_node || type2 == error_mark_node)
+ return false;
+ if (type1 == type2)
+ return true;
+ if (TREE_CODE (type1) != TREE_CODE (type2))
+ return false;
+
+ type1 = rs_build_qualified_type (type1, TYPE_UNQUALIFIED);
+ type2 = rs_build_qualified_type (type2, TYPE_UNQUALIFIED);
+
+ if (TREE_CODE (type1) == ENUMERAL_TYPE)
+ return (TYPE_ALIGN (type1) == TYPE_ALIGN (type2)
+ && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))
+ && same_type_p (finish_underlying_type (type1),
+ finish_underlying_type (type2)));
+
+ if (CLASS_TYPE_P (type1) && std_layout_type_p (type1)
+ && std_layout_type_p (type2) && TYPE_ALIGN (type1) == TYPE_ALIGN (type2)
+ && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)))
+ {
+ tree field1 = TYPE_FIELDS (type1);
+ tree field2 = TYPE_FIELDS (type2);
+ if (TREE_CODE (type1) == RECORD_TYPE)
+ {
+ while (1)
+ {
+ if (!next_common_initial_seqence (field1, field2))
+ return false;
+ if (field1 == NULL_TREE)
+ return true;
+ field1 = DECL_CHAIN (field1);
+ field2 = DECL_CHAIN (field2);
+ }
+ }
+ /* Otherwise both types must be union types.
+ The standard says:
+ "Two standard-layout unions are layout-compatible if they have
+ the same number of non-static data members and corresponding
+ non-static data members (in any order) have layout-compatible
+ types."
+ but the code anticipates that bitfield vs. non-bitfield,
+ different bitfield widths or presence/absence of
+ [[no_unique_address]] should be checked as well. */
+ auto_vec<tree, 16> vec;
+ unsigned int count = 0;
+ for (; field1; field1 = DECL_CHAIN (field1))
+ if (TREE_CODE (field1) == FIELD_DECL)
+ count++;
+ for (; field2; field2 = DECL_CHAIN (field2))
+ if (TREE_CODE (field2) == FIELD_DECL)
+ vec.safe_push (field2);
+ /* Discussions on core lean towards treating multiple union fields
+ of the same type as the same field, so this might need changing
+ in the future. */
+ if (count != vec.length ())
+ return false;
+ for (field1 = TYPE_FIELDS (type1); field1; field1 = DECL_CHAIN (field1))
+ {
+ if (TREE_CODE (field1) != FIELD_DECL)
+ continue;
+ unsigned int j;
+ tree t1 = DECL_BIT_FIELD_TYPE (field1);
+ if (t1 == NULL_TREE)
+ t1 = TREE_TYPE (field1);
+ FOR_EACH_VEC_ELT (vec, j, field2)
+ {
+ tree t2 = DECL_BIT_FIELD_TYPE (field2);
+ if (t2 == NULL_TREE)
+ t2 = TREE_TYPE (field2);
+ if (DECL_BIT_FIELD_TYPE (field1))
+ {
+ if (!DECL_BIT_FIELD_TYPE (field2))
+ continue;
+ if (TYPE_PRECISION (TREE_TYPE (field1))
+ != TYPE_PRECISION (TREE_TYPE (field2)))
+ continue;
+ }
+ else if (DECL_BIT_FIELD_TYPE (field2))
+ continue;
+ if (!layout_compatible_type_p (t1, t2))
+ continue;
+ if ((!lookup_attribute ("no_unique_address",
+ DECL_ATTRIBUTES (field1)))
+ != !lookup_attribute ("no_unique_address",
+ DECL_ATTRIBUTES (field2)))
+ continue;
+ break;
+ }
+ if (j == vec.length ())
+ return false;
+ vec.unordered_remove (j);
+ }
+ return true;
+ }
+
+ return same_type_p (type1, type2);
+}
+
+// forked from gcc/cp/semnatics.cc is_corresponding_member_union
+
+/* Helper function for is_corresponding_member_aggr. Return true if
+ MEMBERTYPE pointer-to-data-member ARG can be found in anonymous
+ union or structure BASETYPE. */
+
+static bool
+is_corresponding_member_union (tree basetype, tree membertype, tree arg)
+{
+ for (tree field = TYPE_FIELDS (basetype); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) != FIELD_DECL || DECL_BIT_FIELD_TYPE (field))
+ continue;
+ else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field),
+ membertype))
+ {
+ if (TREE_CODE (arg) != INTEGER_CST
+ || tree_int_cst_equal (arg, byte_position (field)))
+ return true;
+ }
+ else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+ {
+ tree narg = arg;
+ if (TREE_CODE (basetype) != UNION_TYPE
+ && TREE_CODE (narg) == INTEGER_CST)
+ narg = size_binop (MINUS_EXPR, arg, byte_position (field));
+ if (is_corresponding_member_union (TREE_TYPE (field), membertype, narg))
+ return true;
+ }
+ return false;
+}
+
+// forked from gcc/cp/typeck.cc next_common_initial_seqence
+
+/* Helper function for layout_compatible_type_p and
+ is_corresponding_member_aggr. Advance to next members (NULL if
+ no further ones) and return true if those members are still part of
+ the common initial sequence. */
+
+bool
+next_common_initial_seqence (tree &memb1, tree &memb2)
+{
+ while (memb1)
+ {
+ if (TREE_CODE (memb1) != FIELD_DECL
+ || (DECL_FIELD_IS_BASE (memb1) && is_empty_field (memb1)))
+ {
+ memb1 = DECL_CHAIN (memb1);
+ continue;
+ }
+ if (DECL_FIELD_IS_BASE (memb1))
+ {
+ memb1 = TYPE_FIELDS (TREE_TYPE (memb1));
+ continue;
+ }
+ break;
+ }
+ while (memb2)
+ {
+ if (TREE_CODE (memb2) != FIELD_DECL
+ || (DECL_FIELD_IS_BASE (memb2) && is_empty_field (memb2)))
+ {
+ memb2 = DECL_CHAIN (memb2);
+ continue;
+ }
+ if (DECL_FIELD_IS_BASE (memb2))
+ {
+ memb2 = TYPE_FIELDS (TREE_TYPE (memb2));
+ continue;
+ }
+ break;
+ }
+ if (memb1 == NULL_TREE && memb2 == NULL_TREE)
+ return true;
+ if (memb1 == NULL_TREE || memb2 == NULL_TREE)
+ return false;
+ if (DECL_BIT_FIELD_TYPE (memb1))
+ {
+ if (!DECL_BIT_FIELD_TYPE (memb2))
+ return false;
+ if (!layout_compatible_type_p (DECL_BIT_FIELD_TYPE (memb1),
+ DECL_BIT_FIELD_TYPE (memb2)))
+ return false;
+ if (TYPE_PRECISION (TREE_TYPE (memb1))
+ != TYPE_PRECISION (TREE_TYPE (memb2)))
+ return false;
+ }
+ else if (DECL_BIT_FIELD_TYPE (memb2))
+ return false;
+ else if (!layout_compatible_type_p (TREE_TYPE (memb1), TREE_TYPE (memb2)))
+ return false;
+ if ((!lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb1)))
+ != !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb2)))
+ return false;
+ if (!tree_int_cst_equal (bit_position (memb1), bit_position (memb2)))
+ return false;
+ return true;
+}
+
+// forked from gcc/cp/semantics.cc is_corresponding_member_aggr
+
+/* Helper function for fold_builtin_is_corresponding_member call.
+ Return boolean_false_node if MEMBERTYPE1 BASETYPE1::*ARG1 and
+ MEMBERTYPE2 BASETYPE2::*ARG2 aren't corresponding members,
+ boolean_true_node if they are corresponding members, or for
+ non-constant ARG2 the highest member offset for corresponding
+ members. */
+
+static tree
+is_corresponding_member_aggr (location_t loc, tree basetype1, tree membertype1,
+ tree arg1, tree basetype2, tree membertype2,
+ tree arg2)
+{
+ tree field1 = TYPE_FIELDS (basetype1);
+ tree field2 = TYPE_FIELDS (basetype2);
+ tree ret = boolean_false_node;
+ while (1)
+ {
+ bool r = next_common_initial_seqence (field1, field2);
+ if (field1 == NULL_TREE || field2 == NULL_TREE)
+ break;
+ if (r
+ && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field1),
+ membertype1)
+ && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field2),
+ membertype2))
+ {
+ tree pos = byte_position (field1);
+ if (TREE_CODE (arg1) == INTEGER_CST && tree_int_cst_equal (arg1, pos))
+ {
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ return boolean_true_node;
+ return pos;
+ }
+ else if (TREE_CODE (arg1) != INTEGER_CST)
+ ret = pos;
+ }
+ else if (ANON_AGGR_TYPE_P (TREE_TYPE (field1))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field2)))
+ {
+ if ((!lookup_attribute ("no_unique_address",
+ DECL_ATTRIBUTES (field1)))
+ != !lookup_attribute ("no_unique_address",
+ DECL_ATTRIBUTES (field2)))
+ break;
+ if (!tree_int_cst_equal (bit_position (field1),
+ bit_position (field2)))
+ break;
+ bool overlap = true;
+ tree pos = byte_position (field1);
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ {
+ tree off1 = fold_convert (sizetype, arg1);
+ tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (field1));
+ if (tree_int_cst_lt (off1, pos)
+ || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz1), off1))
+ overlap = false;
+ }
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ {
+ tree off2 = fold_convert (sizetype, arg2);
+ tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (field2));
+ if (tree_int_cst_lt (off2, pos)
+ || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz2), off2))
+ overlap = false;
+ }
+ if (overlap && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field1))
+ && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field2)))
+ {
+ tree narg1 = arg1;
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ narg1
+ = size_binop (MINUS_EXPR, fold_convert (sizetype, arg1), pos);
+ tree narg2 = arg2;
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ narg2
+ = size_binop (MINUS_EXPR, fold_convert (sizetype, arg2), pos);
+ tree t1 = TREE_TYPE (field1);
+ tree t2 = TREE_TYPE (field2);
+ tree nret
+ = is_corresponding_member_aggr (loc, t1, membertype1, narg1, t2,
+ membertype2, narg2);
+ if (nret != boolean_false_node)
+ {
+ if (nret == boolean_true_node)
+ return nret;
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ return size_binop (PLUS_EXPR, nret, pos);
+ ret = size_binop (PLUS_EXPR, nret, pos);
+ }
+ }
+ else if (overlap && TREE_CODE (TREE_TYPE (field1)) == UNION_TYPE
+ && TREE_CODE (TREE_TYPE (field2)) == UNION_TYPE)
+ {
+ tree narg1 = arg1;
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ narg1
+ = size_binop (MINUS_EXPR, fold_convert (sizetype, arg1), pos);
+ tree narg2 = arg2;
+ if (TREE_CODE (arg2) == INTEGER_CST)
+ narg2
+ = size_binop (MINUS_EXPR, fold_convert (sizetype, arg2), pos);
+ if (is_corresponding_member_union (TREE_TYPE (field1),
+ membertype1, narg1)
+ && is_corresponding_member_union (TREE_TYPE (field2),
+ membertype2, narg2))
+ {
+ sorry_at (loc, "%<__builtin_is_corresponding_member%> "
+ "not well defined for anonymous unions");
+ return boolean_false_node;
+ }
+ }
+ }
+ if (!r)
+ break;
+ field1 = DECL_CHAIN (field1);
+ field2 = DECL_CHAIN (field2);
+ }
+ return ret;
+}
+
+// forked from gcc/cp/call.cc null_member_pointer_value_p
+
+/* Returns true iff T is a null member pointer value (4.11). */
+
+bool
+null_member_pointer_value_p (tree t)
+{
+ tree type = TREE_TYPE (t);
+ if (!type)
+ return false;
+ else if (TYPE_PTRMEMFUNC_P (type))
+ return (TREE_CODE (t) == CONSTRUCTOR && CONSTRUCTOR_NELTS (t)
+ && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
+ else if (TYPE_PTRDATAMEM_P (type))
+ return integer_all_onesp (t);
+ else
+ return false;
+}
+
+// forked from gcc/cp/semantics.cc fold_builtin_is_corresponding_member
+
+/* Fold __builtin_is_corresponding_member call. */
+
+tree
+fold_builtin_is_corresponding_member (location_t loc, int nargs, tree *args)
+{
+ /* Unless users call the builtin directly, the following 3 checks should be
+ ensured from std::is_corresponding_member function template. */
+ if (nargs != 2)
+ {
+ error_at (loc, "%<__builtin_is_corresponding_member%> "
+ "needs two arguments");
+ return boolean_false_node;
+ }
+ tree arg1 = args[0];
+ tree arg2 = args[1];
+ if (error_operand_p (arg1) || error_operand_p (arg2))
+ return boolean_false_node;
+ if (!TYPE_PTRMEM_P (TREE_TYPE (arg1)) || !TYPE_PTRMEM_P (TREE_TYPE (arg2)))
+ {
+ error_at (loc, "%<__builtin_is_corresponding_member%> "
+ "argument is not pointer to member");
+ return boolean_false_node;
+ }
+
+ if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg1))
+ || !TYPE_PTRDATAMEM_P (TREE_TYPE (arg2)))
+ return boolean_false_node;
+
+ tree membertype1 = TREE_TYPE (TREE_TYPE (arg1));
+ tree basetype1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg1));
+ if (!complete_type_or_else (basetype1, NULL_TREE))
+ return boolean_false_node;
+
+ tree membertype2 = TREE_TYPE (TREE_TYPE (arg2));
+ tree basetype2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg2));
+ if (!complete_type_or_else (basetype2, NULL_TREE))
+ return boolean_false_node;
+
+ if (!NON_UNION_CLASS_TYPE_P (basetype1) || !NON_UNION_CLASS_TYPE_P (basetype2)
+ || !std_layout_type_p (basetype1) || !std_layout_type_p (basetype2))
+ return boolean_false_node;
+
+ /* If the member types aren't layout compatible, then they
+ can't be corresponding members. */
+ if (!layout_compatible_type_p (membertype1, membertype2))
+ return boolean_false_node;
+
+ if (null_member_pointer_value_p (arg1) || null_member_pointer_value_p (arg2))
+ return boolean_false_node;
+
+ if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST
+ && !tree_int_cst_equal (arg1, arg2))
+ return boolean_false_node;
+
+ if (TREE_CODE (arg2) == INTEGER_CST && TREE_CODE (arg1) != INTEGER_CST)
+ {
+ std::swap (arg1, arg2);
+ std::swap (membertype1, membertype2);
+ std::swap (basetype1, basetype2);
+ }
+
+ tree ret = is_corresponding_member_aggr (loc, basetype1, membertype1, arg1,
+ basetype2, membertype2, arg2);
+ if (TREE_TYPE (ret) == boolean_type_node)
+ return ret;
+ /* If both arg1 and arg2 are INTEGER_CSTs, is_corresponding_member_aggr
+ already returns boolean_{true,false}_node whether those particular
+ members are corresponding members or not. Otherwise, if only
+ one of them is INTEGER_CST (canonicalized to first being INTEGER_CST
+ above), it returns boolean_false_node if it is certainly not a
+ corresponding member and otherwise we need to do a runtime check that
+ those two OFFSET_TYPE offsets are equal.
+ If neither of the operands is INTEGER_CST, is_corresponding_member_aggr
+ returns the largest offset at which the members would be corresponding
+ members, so perform arg1 <= ret && arg1 == arg2 runtime check. */
+ gcc_assert (TREE_CODE (arg2) != INTEGER_CST);
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ return fold_build2 (EQ_EXPR, boolean_type_node, arg1,
+ fold_convert (TREE_TYPE (arg1), arg2));
+ ret = fold_build2 (LE_EXPR, boolean_type_node,
+ fold_convert (pointer_sized_int_node, arg1),
+ fold_convert (pointer_sized_int_node, ret));
+ return fold_build2 (TRUTH_AND_EXPR, boolean_type_node, ret,
+ fold_build2 (EQ_EXPR, boolean_type_node, arg1,
+ fold_convert (TREE_TYPE (arg1), arg2)));
+}
+
+// forked from gcc/cp/tree.cc lvalue_type
+
+/* The type of ARG when used as an lvalue. */
+
+tree
+lvalue_type (tree arg)
+{
+ tree type = TREE_TYPE (arg);
+ return type;
+}
+
+// forked from gcc/c-family/c-warn.cc lvalue_error
+
+/* Print an error message for an invalid lvalue. USE says
+ how the lvalue is being used and so selects the error message. LOC
+ is the location for the error. */
+
+void
+lvalue_error (location_t loc, enum lvalue_use use)
+{
+ switch (use)
+ {
+ case lv_assign:
+ error_at (loc, "lvalue required as left operand of assignment");
+ break;
+ case lv_increment:
+ error_at (loc, "lvalue required as increment operand");
+ break;
+ case lv_decrement:
+ error_at (loc, "lvalue required as decrement operand");
+ break;
+ case lv_addressof:
+ error_at (loc, "lvalue required as unary %<&%> operand");
+ break;
+ case lv_asm:
+ error_at (loc, "lvalue required in %<asm%> statement");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+// forked from gcc/cp/cp--gimplify.cc cp_fold_maybe_rvalue
+
+/* Fold expression X which is used as an rvalue if RVAL is true. */
+
+tree
+cp_fold_maybe_rvalue (tree x, bool rval)
+{
+ while (true)
+ {
+ x = fold (x);
+ if (rval)
+ x = mark_rvalue_use (x);
+ if (rval && DECL_P (x) && !TYPE_REF_P (TREE_TYPE (x)))
+ {
+ tree v = decl_constant_value (x);
+ if (v != x && v != error_mark_node)
+ {
+ x = v;
+ continue;
+ }
+ }
+ break;
+ }
+ return x;
+}
+
+// forked from gcc/cp/cp--gimplify.cc cp_fold_rvalue
+
+/* Fold expression X which is used as an rvalue. */
+
+tree
+cp_fold_rvalue (tree x)
+{
+ return cp_fold_maybe_rvalue (x, true);
+}
+
+/* Returns true iff class T has a constexpr destructor or has an
+ implicitly declared destructor that we can't tell if it's constexpr
+ without forcing a lazy declaration (which might cause undesired
+ instantiations). */
+
+static bool
+type_maybe_constexpr_destructor (tree t)
+{
+ /* Until C++20, only trivial destruction is constexpr. */
+ if (TYPE_HAS_TRIVIAL_DESTRUCTOR (t))
+ return true;
+
+ if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DESTRUCTOR (t))
+ /* Assume it's constexpr. */
+ return true;
+ tree fn = CLASSTYPE_DESTRUCTOR (t);
+ return (fn && Compile::maybe_constexpr_fn (fn));
+}
+
+/* T is a non-literal type used in a context which requires a constant
+ expression. Explain why it isn't literal. */
+
+void
+explain_non_literal_class (tree t)
+{
+ static hash_set<tree> *diagnosed;
+
+ if (!CLASS_TYPE_P (t))
+ return;
+ t = TYPE_MAIN_VARIANT (t);
+
+ if (diagnosed == NULL)
+ diagnosed = new hash_set<tree>;
+ if (diagnosed->add (t))
+ /* Already explained. */
+ return;
+
+ auto_diagnostic_group d;
+ inform (UNKNOWN_LOCATION, "%q+T is not literal because:", t);
+ if (LAMBDA_TYPE_P (t))
+ inform (UNKNOWN_LOCATION,
+ " %qT is a closure type, which is only literal in "
+ "C++17 and later",
+ t);
+ else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+ && !type_maybe_constexpr_destructor (t))
+ inform (UNKNOWN_LOCATION, " %q+T does not have %<constexpr%> destructor",
+ t);
+ else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+ inform (UNKNOWN_LOCATION, " %q+T has a non-trivial destructor", t);
+ else if (CLASSTYPE_NON_AGGREGATE (t) && !TYPE_HAS_TRIVIAL_DFLT (t)
+ && !LAMBDA_TYPE_P (t) && !TYPE_HAS_CONSTEXPR_CTOR (t))
+ {
+ inform (UNKNOWN_LOCATION,
+ " %q+T is not an aggregate, does not have a trivial "
+ "default constructor, and has no %<constexpr%> constructor that "
+ "is not a copy or move constructor",
+ t);
+ if (type_has_non_user_provided_default_constructor (t))
+ /* Note that we can't simply call locate_ctor because when the
+ constructor is deleted it just returns NULL_TREE. */
+ for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+ {
+ tree fn = *iter;
+ tree parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+
+ parms = skip_artificial_parms_for (fn, parms);
+
+ if (sufficient_parms_p (parms))
+ {
+ Compile::explain_invalid_constexpr_fn (fn);
+ break;
+ }
+ }
+ }
+ else
+ {
+ tree binfo, base_binfo, field;
+ int i;
+ for (binfo = TYPE_BINFO (t), i = 0;
+ BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree basetype = TREE_TYPE (base_binfo);
+ if (!CLASSTYPE_LITERAL_P (basetype))
+ {
+ inform (UNKNOWN_LOCATION,
+ " base class %qT of %q+T is non-literal", basetype, t);
+ explain_non_literal_class (basetype);
+ return;
+ }
+ }
+ for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ {
+ tree ftype;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+ ftype = TREE_TYPE (field);
+ if (!Compile::literal_type_p (ftype))
+ {
+ inform (DECL_SOURCE_LOCATION (field),
+ " non-static data member %qD has non-literal type",
+ field);
+ if (CLASS_TYPE_P (ftype))
+ explain_non_literal_class (ftype);
+ }
+ if (RS_TYPE_VOLATILE_P (ftype))
+ inform (DECL_SOURCE_LOCATION (field),
+ " non-static data member %qD has volatile type", field);
+ }
+ }
+}
+
+// forked from gcc/cp/call.cc reference_related_p
+
+/* Returns nonzero if T1 is reference-related to T2. */
+
+bool
+reference_related_p (tree t1, tree t2)
+{
+ if (t1 == error_mark_node || t2 == error_mark_node)
+ return false;
+
+ t1 = TYPE_MAIN_VARIANT (t1);
+ t2 = TYPE_MAIN_VARIANT (t2);
+
+ /* [dcl.init.ref]
+
+ Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related
+ to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */
+ return (similar_type_p (t1, t2)
+ /*|| (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2)
+ && DERIVED_FROM_P (t1, t2))*/);
+}
+
+// forked from gcc/cp/typeck2.cc ordinary_char_type_p
+
+/* True iff TYPE is a C++20 "ordinary" character type. */
+
+bool
+ordinary_char_type_p (tree type)
+{
+ type = TYPE_MAIN_VARIANT (type);
+ return (type == char_type_node || type == signed_char_type_node
+ || type == unsigned_char_type_node);
+}
+
+// forked from gcc/cp/typeck2.cc array_string_literal_compatible_p
+
+/* True iff the string literal INIT has a type suitable for initializing array
+ TYPE. */
+
+bool
+array_string_literal_compatible_p (tree type, tree init)
+{
+ tree to_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ tree from_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init)));
+
+ if (to_char_type == from_char_type)
+ return true;
+ /* The array element type does not match the initializing string
+ literal element type; this is only allowed when both types are
+ ordinary character type. There are no string literals of
+ signed or unsigned char type in the language, but we can get
+ them internally from converting braced-init-lists to
+ STRING_CST. */
+ if (ordinary_char_type_p (to_char_type)
+ && ordinary_char_type_p (from_char_type))
+ return true;
+ return false;
+}
+
} // namespace Rust