* class.c (add_method): Move slot search and insertion to ...
* name-lookup.c (get_method_slot): ... this new function.
(lookup_fnfields_slot_nolazy): Cope with NULL slot.
* name-lookup.h (get_method_slot): Declare.
* decl.c (cxx_init_decl_processinng): Give conv_op_marker a more
realistic type.
(grok_special_member_properties): Set
TYPE_HAS_CONVERSION. Expicitly look at DECL_NAME for specialness.
Improve TYPE_HAS_CONSTEXPR_CTOR setting.
From-SVN: r251737
2017-09-05 Nathan Sidwell <nathan@acm.org>
+ * class.c (add_method): Move slot search and insertion to ...
+ * name-lookup.c (get_method_slot): ... this new function.
+ (lookup_fnfields_slot_nolazy): Cope with NULL slot.
+ * name-lookup.h (get_method_slot): Declare.
+ * decl.c (cxx_init_decl_processinng): Give conv_op_marker a more
+ realistic type.
+ (grok_special_member_properties): Set
+ TYPE_HAS_CONVERSION. Expicitly look at DECL_NAME for specialness.
+ Improve TYPE_HAS_CONSTEXPR_CTOR setting.
+
* cp-tree.h (lang_decl_base): Rename template_conv_p to
unknown_bound_p.
(DECL_CONV_FN_P): Don't check NULL DECL_NAME.
if (method == error_mark_node)
return false;
- vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (type);
- if (!method_vec)
- {
- /* Make a new method vector. We start with 8 entries. */
- vec_alloc (method_vec, 8);
- CLASSTYPE_METHOD_VEC (type) = method_vec;
- }
-
/* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc. */
grok_special_member_properties (method);
- bool insert_p = true;
- tree method_name = DECL_NAME (method);
- bool complete_p = COMPLETE_TYPE_P (type);
- bool conv_p = IDENTIFIER_CONV_OP_P (method_name);
-
- if (conv_p)
- method_name = conv_op_identifier;
-
- /* See if we already have an entry with this name. */
- unsigned slot;
- tree m;
- for (slot = 0; vec_safe_iterate (method_vec, slot, &m); ++slot)
- {
- m = DECL_NAME (OVL_FIRST (m));
- if (m == method_name)
- {
- insert_p = false;
- break;
- }
- if (complete_p && m > method_name)
- break;
- }
- tree current_fns = insert_p ? NULL_TREE : (*method_vec)[slot];
+ tree *slot = get_method_slot (type, DECL_NAME (method));
+ tree current_fns = *slot;
- tree conv_marker = NULL_TREE;
- if (conv_p)
- {
- /* For conversion operators, we prepend a dummy overload
- pointing at conv_op_marker. That function's DECL_NAME is
- conv_op_identifier, so we can use identifier equality to
- locate it. */
- if (current_fns)
- {
- gcc_checking_assert (OVL_FUNCTION (current_fns) == conv_op_marker);
- conv_marker = current_fns;
- current_fns = OVL_CHAIN (current_fns);
- }
- else
- conv_marker = ovl_make (conv_op_marker, NULL_TREE);
- }
gcc_assert (!DECL_EXTERN_C_P (method));
/* Check to see if we've already got this method. */
current_fns = ovl_insert (method, current_fns, via_using);
- if (conv_p)
- {
- TYPE_HAS_CONVERSION (type) = 1;
- /* Prepend the marker function. */
- OVL_CHAIN (conv_marker) = current_fns;
- current_fns = conv_marker;
- }
- else if (!complete_p && !IDENTIFIER_CDTOR_P (DECL_NAME (method)))
+ if (!DECL_CONV_FN_P (method) && !COMPLETE_TYPE_P (type))
push_class_level_binding (DECL_NAME (method), current_fns);
- if (insert_p)
- {
- bool reallocated;
+ *slot = current_fns;
- /* We only expect to add few methods in the COMPLETE_P case, so
- just make room for one more method in that case. */
- if (complete_p)
- reallocated = vec_safe_reserve_exact (method_vec, 1);
- else
- reallocated = vec_safe_reserve (method_vec, 1);
- if (reallocated)
- CLASSTYPE_METHOD_VEC (type) = method_vec;
- if (slot == method_vec->length ())
- method_vec->quick_push (current_fns);
- else
- method_vec->quick_insert (slot, current_fns);
- }
- else
- /* Replace the current slot. */
- (*method_vec)[slot] = current_fns;
return true;
}
noexcept_deferred_spec = build_tree_list (make_node (DEFERRED_NOEXCEPT),
NULL_TREE);
- /* Create the conversion operator marker. This operator's DECL_NAME
- is in the identifier table, so we can use identifier equality to
- find it. This has no type and no context, so we can't
- accidentally think it a real function. */
- conv_op_marker = build_lang_decl (FUNCTION_DECL, conv_op_identifier,
- NULL_TREE);
-
#if 0
record_builtin_type (RID_MAX, NULL, string_type_node);
#endif
void_ftype_ptr
= build_exception_variant (void_ftype_ptr, empty_except_spec);
+ /* Create the conversion operator marker. This operator's DECL_NAME
+ is in the identifier table, so we can use identifier equality to
+ find it. */
+ conv_op_marker = build_lang_decl (FUNCTION_DECL, conv_op_identifier,
+ void_ftype);
+
/* C++ extensions */
unknown_type_node = make_node (LANG_TYPE);
return;
class_type = DECL_CONTEXT (decl);
- if (DECL_CONSTRUCTOR_P (decl))
+ if (IDENTIFIER_CTOR_P (DECL_NAME (decl)))
{
int ctor = copy_fn_p (decl);
TYPE_HAS_LIST_CTOR (class_type) = 1;
if (DECL_DECLARED_CONSTEXPR_P (decl)
- && !copy_fn_p (decl) && !move_fn_p (decl))
+ && !ctor && !move_fn_p (decl))
TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
}
- else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
+ else if (DECL_NAME (decl) == cp_assignment_operator_id (NOP_EXPR))
{
/* [class.copy]
else if (move_fn_p (decl) && user_provided_p (decl))
TYPE_HAS_COMPLEX_MOVE_ASSIGN (class_type) = 1;
}
+ else if (IDENTIFIER_CONV_OP_P (DECL_NAME (decl)))
+ TYPE_HAS_CONVERSION (class_type) = true;
+
/* Destructors are handled in check_methods. */
}
}
else
for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i)
- {
- if (OVL_NAME (fns) == lookup)
- {
- val = fns;
- break;
- }
- }
+ /* We can get a NULL binding during insertion of a new
+ method name, because the identifier_binding machinery
+ performs a lookup. If we find such a NULL slot, that's
+ the thing we were looking for, so we might as well bail
+ out immediately. */
+ if (!fns)
+ break;
+ else if (OVL_NAME (fns) == lookup)
+ {
+ val = fns;
+ break;
+ }
/* Extract the conversion operators asked for, unless the general
conversion operator was requested. */
return lookup_fnfields_slot_nolazy (type, name);
}
+/* Find the slot containing overloads called 'NAME'. If there is no
+ such slot, create an empty one. KLASS might be complete at this
+ point, in which case we need to preserve ordering. Deals with
+ conv_op marker handling. */
+
+tree *
+get_method_slot (tree klass, tree name)
+{
+ bool complete_p = COMPLETE_TYPE_P (klass);
+
+ vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (klass);
+ if (!method_vec)
+ {
+ vec_alloc (method_vec, 8);
+ CLASSTYPE_METHOD_VEC (klass) = method_vec;
+ }
+
+ if (IDENTIFIER_CONV_OP_P (name))
+ name = conv_op_identifier;
+
+ unsigned ix, length = method_vec->length ();
+ for (ix = 0; ix < length; ix++)
+ {
+ tree *slot = &(*method_vec)[ix];
+ tree fn_name = OVL_NAME (*slot);
+
+ if (fn_name == name)
+ {
+ if (name == conv_op_identifier)
+ {
+ gcc_checking_assert (OVL_FUNCTION (*slot) == conv_op_marker);
+ /* Skip the conv-op marker. */
+ slot = &OVL_CHAIN (*slot);
+ }
+ return slot;
+ }
+
+ if (complete_p && fn_name > name)
+ break;
+ }
+
+ /* No slot found. Create one at IX. We know in this case that our
+ caller will succeed in adding the function. */
+ if (complete_p)
+ {
+ /* Do exact allocation when complete, as we don't expect to add
+ many. */
+ vec_safe_reserve_exact (method_vec, 1);
+ method_vec->quick_insert (ix, NULL_TREE);
+ }
+ else
+ {
+ gcc_checking_assert (ix == length);
+ vec_safe_push (method_vec, NULL_TREE);
+ }
+ CLASSTYPE_METHOD_VEC (klass) = method_vec;
+
+ tree *slot = &(*method_vec)[ix];
+ if (name == conv_op_identifier)
+ {
+ /* Install the marker prefix. */
+ *slot = ovl_make (conv_op_marker, NULL_TREE);
+ slot = &OVL_CHAIN (*slot);
+ }
+
+ return slot;
+}
+
static struct {
gt_pointer_operator new_value;
void *cookie;
extern tree lookup_field_1 (tree, tree, bool);
extern tree lookup_fnfields_slot (tree, tree);
extern tree lookup_fnfields_slot_nolazy (tree, tree);
+extern tree *get_method_slot (tree klass, tree name);
extern void resort_type_method_vec (void *, void *,
gt_pointer_operator, void *);
extern void set_class_bindings (tree);