From: Nathan Sidwell Date: Fri, 25 Aug 2017 11:37:10 +0000 (+0000) Subject: Conversion operators have a special name X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bff8b385e997a85cce62031c80bac1b431659fcd;p=gcc.git Conversion operators have a special name Conversion operators have a special name * cp-tree.h (CPTI_CONV_OP_MARKER, CPTI_CONV_OP_IDENTIFIER): New. (conv_op_marker, conv_op_identifier): New. (CLASSTYPE_FIRST_CONVERSION_SLOT): Delete. * decl.c (initialize_predefined_identifiers): Add conv_op_identifier. (cxx_init_decl_processing): Create conv_op_marker. * decl2.c (check_classfn): Lookup conv-ops by name. * class.c (add_method): Use conv_op_identifier & conv_op_marker. (resort_type_method_vec): Don't skip conv-ops. (finish_struct_methods, warn_hidden): Likewise. * name-lookup.h (lookup_all_conversions): Delete. * name-lookup.c (lookup_conversion_operator): Replace with ... (extract_conversion_operator): ... this. (lookup_fnfields_slot_nolazy): Find conv-ops by name. (lookup_all_conversions): Delete. * pt.c (check_explicit_specialization): Find conv-ops by name. * search.c (lookup_conversions_r): Likewise. From-SVN: r251348 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 92ecf91a23e..3557e4881dc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,24 @@ +2017-08-25 Nathan Sidwell + + Conversion operators have a special name + * cp-tree.h (CPTI_CONV_OP_MARKER, CPTI_CONV_OP_IDENTIFIER): New. + (conv_op_marker, conv_op_identifier): New. + (CLASSTYPE_FIRST_CONVERSION_SLOT): Delete. + * decl.c (initialize_predefined_identifiers): Add + conv_op_identifier. + (cxx_init_decl_processing): Create conv_op_marker. + * decl2.c (check_classfn): Lookup conv-ops by name. + * class.c (add_method): Use conv_op_identifier & conv_op_marker. + (resort_type_method_vec): Don't skip conv-ops. + (finish_struct_methods, warn_hidden): Likewise. + * name-lookup.h (lookup_all_conversions): Delete. + * name-lookup.c (lookup_conversion_operator): Replace with ... + (extract_conversion_operator): ... this. + (lookup_fnfields_slot_nolazy): Find conv-ops by name. + (lookup_all_conversions): Delete. + * pt.c (check_explicit_specialization): Find conv-ops by name. + * search.c (lookup_conversions_r): Likewise. + 2017-08-24 Nathan Sidwell Conversion operators kept on single overload set diff --git a/gcc/cp/class.c b/gcc/cp/class.c index a08ce89c66e..fc37bd8aa9c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1017,9 +1017,6 @@ add_method (tree type, tree method, bool via_using) if (method == error_mark_node) return false; - bool complete_p = COMPLETE_TYPE_P (type); - bool conv_p = DECL_CONV_FN_P (method); - vec *method_vec = CLASSTYPE_METHOD_VEC (type); if (!method_vec) { @@ -1032,32 +1029,45 @@ add_method (tree type, tree method, bool via_using) grok_special_member_properties (method); bool insert_p = true; - unsigned slot; - tree m; + 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. */ - for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; - vec_safe_iterate (method_vec, slot, &m); - ++slot) + unsigned slot; + tree m; + for (slot = 0; vec_safe_iterate (method_vec, slot, &m); ++slot) { - m = OVL_FIRST (m); - if (conv_p) - { - if (DECL_CONV_FN_P (m)) - insert_p = false; - break; - } - if (DECL_NAME (m) == DECL_NAME (method)) + m = DECL_NAME (OVL_FIRST (m)); + if (m == method_name) { insert_p = false; break; } - if (complete_p - && !DECL_CONV_FN_P (m) - && DECL_NAME (m) > DECL_NAME (method)) + if (complete_p && m > method_name) break; } tree current_fns = insert_p ? NULL_TREE : (*method_vec)[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. */ @@ -1206,7 +1216,12 @@ 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; + { + 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))) push_class_level_binding (DECL_NAME (method), current_fns); @@ -2294,23 +2309,10 @@ resort_type_method_vec (void* obj, { if (vec *method_vec = (vec *) obj) { - int len = method_vec->length (); - int slot; - - /* The type conversion ops have to live at the front of the vec, so we - can't sort them. */ - for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; - slot < len; slot++) - if (!DECL_CONV_FN_P (OVL_FIRST ((*method_vec)[slot]))) - break; - - if (len > slot + 1) - { - resort_data.new_value = new_value; - resort_data.cookie = cookie; - qsort (method_vec->address () + slot, len - slot, sizeof (tree), - resort_method_name_cmp); - } + resort_data.new_value = new_value; + resort_data.cookie = cookie; + qsort (method_vec->address (), method_vec->length (), sizeof (tree), + resort_method_name_cmp); } } @@ -2323,15 +2325,10 @@ resort_type_method_vec (void* obj, static void finish_struct_methods (tree t) { - vec *method_vec; - int slot, len; - - method_vec = CLASSTYPE_METHOD_VEC (t); + vec *method_vec = CLASSTYPE_METHOD_VEC (t); if (!method_vec) return; - len = method_vec->length (); - /* Clear DECL_IN_AGGR_P for all functions. */ for (tree fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn)) if (DECL_DECLARES_FUNCTION_P (fn)) @@ -2341,17 +2338,8 @@ finish_struct_methods (tree t) no methods, then some public defaults are generated. */ maybe_warn_about_overly_private_class (t); - /* The type conversion ops have to live at the front of the vec, so we - can't sort them. */ - tree fn_fields; - for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; - method_vec->iterate (slot, &fn_fields); - ++slot) - if (!DECL_CONV_FN_P (OVL_FIRST (fn_fields))) - break; - if (len - slot > 1) - qsort (method_vec->address () + slot, - len-slot, sizeof (tree), method_name_cmp); + qsort (method_vec->address (), method_vec->length (), + sizeof (tree), method_name_cmp); } /* Make BINFO's vtable have N entries, including RTTI entries, @@ -3000,12 +2988,9 @@ warn_hidden (tree t) { vec *method_vec = CLASSTYPE_METHOD_VEC (t); tree fns; - size_t i; /* We go through each separately named virtual function. */ - for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; - vec_safe_iterate (method_vec, i, &fns); - ++i) + for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i) { tree fndecl; tree base_binfo; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b915bd9603f..d04c00cf4cf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -125,6 +125,7 @@ enum cp_tree_index CPTI_TYPE_INFO_PTR_TYPE, CPTI_ABORT_FNDECL, CPTI_AGGR_TAG, + CPTI_CONV_OP_MARKER, CPTI_CTOR_IDENTIFIER, CPTI_COMPLETE_CTOR_IDENTIFIER, @@ -133,6 +134,7 @@ enum cp_tree_index CPTI_COMPLETE_DTOR_IDENTIFIER, CPTI_BASE_DTOR_IDENTIFIER, CPTI_DELETING_DTOR_IDENTIFIER, + CPTI_CONV_OP_IDENTIFIER, CPTI_DELTA_IDENTIFIER, CPTI_IN_CHARGE_IDENTIFIER, CPTI_VTT_PARM_IDENTIFIER, @@ -199,6 +201,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define global_type_node cp_global_trees[CPTI_GLOBAL_TYPE] #define const_type_info_type_node cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE] #define type_info_ptr_type cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE] +#define conv_op_marker cp_global_trees[CPTI_CONV_OP_MARKER] #define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL] #define current_aggr cp_global_trees[CPTI_AGGR_TAG] #define nullptr_node cp_global_trees[CPTI_NULLPTR] @@ -239,6 +242,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; /* The name of a destructor that destroys virtual base classes, and then deletes the entire object. */ #define deleting_dtor_identifier cp_global_trees[CPTI_DELETING_DTOR_IDENTIFIER] +/* The name used for conversion operators -- but note that actual + conversion functions use special identifiers outside the identifier + table. */ +#define conv_op_identifier cp_global_trees[CPTI_CONV_OP_IDENTIFIER] /* The name of the identifier used internally to represent operator CODE. */ #define cp_operator_id(CODE) \ @@ -2148,10 +2155,6 @@ struct GTY(()) lang_type { and the RECORD_TYPE for the class template otherwise. */ #define CLASSTYPE_DECL_LIST(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->decl_list) -/* The first slot in the CLASSTYPE_METHOD_VEC where conversion - operators can appear. */ -#define CLASSTYPE_FIRST_CONVERSION_SLOT 0 - /* A FUNCTION_DECL or OVERLOAD for the constructors for NODE. These are the constructors that take an in-charge parameter. */ #define CLASSTYPE_CONSTRUCTORS(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a9d72c0f30d..bd6926a486a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3979,6 +3979,7 @@ initialize_predefined_identifiers (void) {"__dt_base ", &base_dtor_identifier, cik_dtor}, {"__dt_comp ", &complete_dtor_identifier, cik_dtor}, {"__dt_del ", &deleting_dtor_identifier, cik_dtor}, + {"__conv_op ", &conv_op_identifier, cik_conv_op}, {"__in_chrg", &in_charge_identifier, cik_normal}, {"this", &this_identifier, cik_normal}, {"__delta", &delta_identifier, cik_normal}, @@ -4072,6 +4073,13 @@ 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 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 66d206ea851..0f828b57396 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -664,7 +664,7 @@ check_classfn (tree ctype, tree function, tree template_parms) else { if (DECL_CONV_FN_P (function)) - fns = lookup_all_conversions (ctype); + fns = lookup_fnfields_slot (ctype, conv_op_identifier); error_at (DECL_SOURCE_LOCATION (function), "no declaration matches %q#D", function); diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 3d69e1d1c2e..df29331b95d 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -1089,37 +1089,27 @@ lookup_arg_dependent (tree name, tree fns, vec *args) return fns; } -/* Return the conversion operators in CLASS_TYPE corresponding to - "operator TYPE ()". Only CLASS_TYPE itself is searched; this - routine does not scan the base classes of CLASS_TYPE. */ +/* FNS is an overload set of conversion functions. Return the + overloads converting to TYPE. */ static tree -lookup_conversion_operator (tree class_type, tree type) +extract_conversion_operator (tree fns, tree type) { tree convs = NULL_TREE; + tree tpls = NULL_TREE; - if (TYPE_HAS_CONVERSION (class_type)) + for (ovl_iterator iter (fns); iter; ++iter) { - tree fns = NULL_TREE; - tree tpls = NULL_TREE; - vec *methods = CLASSTYPE_METHOD_VEC (class_type); + if (same_type_p (DECL_CONV_FN_TYPE (*iter), type)) + convs = lookup_add (*iter, convs); - vec_safe_iterate (methods, CLASSTYPE_FIRST_CONVERSION_SLOT, &fns); - if (fns && !DECL_CONV_FN_P (OVL_FIRST (fns))) - fns = 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 (TREE_CODE (*iter) == TEMPLATE_DECL) - tpls = lookup_add (*iter, tpls); - } - - if (!convs) - convs = tpls; + if (TREE_CODE (*iter) == TEMPLATE_DECL) + tpls = lookup_add (*iter, tpls); } + if (!convs) + convs = tpls; + return convs; } @@ -1134,48 +1124,56 @@ lookup_fnfields_slot_nolazy (tree type, tree name) if (!method_vec) return NULL_TREE; - if (IDENTIFIER_CONV_OP_P (name)) - return lookup_conversion_operator (type, TREE_TYPE (name)); - - /* Skip the conversion operators. */ - int i; + /* 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; tree fns; - for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; - vec_safe_iterate (method_vec, i, &fns); - ++i) - if (!DECL_CONV_FN_P (OVL_FIRST (fns))) - break; /* If the type is complete, use binary search. */ if (COMPLETE_TYPE_P (type)) { - int lo; - int hi; - - lo = i; - hi = method_vec->length (); + int lo = 0; + int hi = method_vec->length (); while (lo < hi) { - i = (lo + hi) / 2; + int i = (lo + hi) / 2; fns = (*method_vec)[i]; tree fn_name = OVL_NAME (fns); - if (fn_name > name) + if (fn_name > lookup) hi = i; - else if (fn_name < name) + else if (fn_name < lookup) lo = i + 1; else - return fns; + { + val = fns; + break; + } } } else - for (; vec_safe_iterate (method_vec, i, &fns); ++i) + for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i) { - if (OVL_NAME (fns) == name) - return fns; + if (OVL_NAME (fns) == lookup) + { + val = fns; + break; + } } - return NULL_TREE; + /* 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; } /* Do a 1-level search for NAME as a member of TYPE. The caller must @@ -1314,30 +1312,6 @@ lookup_fnfields_slot (tree type, tree name) return lookup_fnfields_slot_nolazy (type, name); } -/* Collect all the conversion operators of KLASS. */ - -tree -lookup_all_conversions (tree klass) -{ - tree lkp = NULL_TREE; - - if (vec *methods = CLASSTYPE_METHOD_VEC (klass)) - { - tree ovl; - for (int idx = CLASSTYPE_FIRST_CONVERSION_SLOT; - methods->iterate (idx, &ovl); ++idx) - { - if (!DECL_CONV_FN_P (OVL_FIRST (ovl))) - /* There are no more conversion functions. */ - break; - - lkp = lookup_add (ovl, lkp); - } - } - - return lkp; -} - /* Compute the chain index of a binding_entry given the HASH value of its name and the total COUNT of chains. COUNT is assumed to be a power of 2. */ diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 1f671479fec..99f9b9bb45d 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -322,7 +322,6 @@ 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 lookup_all_conversions (tree); extern tree innermost_non_namespace_value (tree); extern cxx_binding *outer_binding (tree, cxx_binding *, bool); extern void cp_emit_debug_info_for_using (tree, tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8d816c73244..564ffb05f28 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2894,16 +2894,13 @@ check_explicit_specialization (tree declarator, name = DECL_NAME (decl); } - tree fns = NULL_TREE; - if (DECL_CONV_FN_P (decl)) - /* For a type-conversion operator, we cannot do a - name-based lookup. We might be looking for `operator - int' which will be a specialization of `operator T'. - Grab all the conversion operators, and then select from - them. */ - fns = lookup_all_conversions (ctype); - else - fns = lookup_fnfields_slot_nolazy (ctype, name); + /* For a type-conversion operator, We might be looking for + `operator int' which will be a specialization of + `operator T'. Grab all the conversion operators, and + then select from them. */ + tree fns = lookup_fnfields_slot_nolazy (ctype, + IDENTIFIER_CONV_OP_P (name) + ? conv_op_identifier : name); if (fns == NULL_TREE) { diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 31f4dd66b9f..266d8dd36d6 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -2370,12 +2370,8 @@ lookup_conversions_r (tree binfo, int virtual_depth, int virtualness, virtual_depth++; /* First, locate the unhidden ones at this level. */ - vec *method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo)); - tree conv = NULL_TREE; - vec_safe_iterate (method_vec, CLASSTYPE_FIRST_CONVERSION_SLOT, &conv); - if (conv && !DECL_CONV_FN_P (OVL_FIRST (conv))) - conv = NULL_TREE; - + tree conv = lookup_fnfields_slot_nolazy (BINFO_TYPE (binfo), + conv_op_identifier); for (ovl_iterator iter (conv); iter; ++iter) { tree fn = *iter;