From fcaf306523baa9883c680a3a894bb5ff43092073 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 5 Sep 2017 20:13:10 +0000 Subject: [PATCH] class.c (add_method): Move slot search and insertion to ... * 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 --- gcc/cp/ChangeLog | 10 ++++++ gcc/cp/class.c | 78 +++------------------------------------------- gcc/cp/decl.c | 22 +++++++------ gcc/cp/name-lookup.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++----- gcc/cp/name-lookup.h | 1 + 5 files changed, 107 insertions(+), 91 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6d31718..637b788 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,15 @@ 2017-09-05 Nathan Sidwell + * 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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 9e740db..d04c2ac 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1011,57 +1011,12 @@ add_method (tree type, tree method, bool via_using) if (method == error_mark_node) return false; - vec *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. */ @@ -1209,36 +1164,11 @@ add_method (tree type, tree method, bool via_using) 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; } diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 861dfcf..da5e16b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4073,13 +4073,6 @@ cxx_init_decl_processing (void) 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 @@ -4094,6 +4087,12 @@ cxx_init_decl_processing (void) 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); @@ -12793,7 +12792,7 @@ grok_special_member_properties (tree decl) return; class_type = DECL_CONTEXT (decl); - if (DECL_CONSTRUCTOR_P (decl)) + if (IDENTIFIER_CTOR_P (DECL_NAME (decl))) { int ctor = copy_fn_p (decl); @@ -12823,10 +12822,10 @@ grok_special_member_properties (tree 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] @@ -12847,6 +12846,9 @@ grok_special_member_properties (tree decl) 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. */ } diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index f4b9ff1..eacd515 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1155,13 +1155,18 @@ lookup_fnfields_slot_nolazy (tree type, tree name) } 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. */ @@ -1312,6 +1317,74 @@ lookup_fnfields_slot (tree type, tree name) 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 *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; diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 94d2aaa..aa96e15 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -322,6 +322,7 @@ extern tree lookup_arg_dependent (tree, tree, vec *); 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); -- 2.7.4