+2017-08-25 Nathan Sidwell <nathan@acm.org>
+
+ 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 <nathan@acm.org>
Conversion operators kept on single overload set
if (method == error_mark_node)
return false;
- bool complete_p = COMPLETE_TYPE_P (type);
- bool conv_p = DECL_CONV_FN_P (method);
-
vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (type);
if (!method_vec)
{
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. */
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);
{
if (vec<tree, va_gc> *method_vec = (vec<tree, va_gc> *) 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);
}
}
static void
finish_struct_methods (tree t)
{
- vec<tree, va_gc> *method_vec;
- int slot, len;
-
- method_vec = CLASSTYPE_METHOD_VEC (t);
+ vec<tree, va_gc> *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))
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,
{
vec<tree, va_gc> *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;
CPTI_TYPE_INFO_PTR_TYPE,
CPTI_ABORT_FNDECL,
CPTI_AGGR_TAG,
+ CPTI_CONV_OP_MARKER,
CPTI_CTOR_IDENTIFIER,
CPTI_COMPLETE_CTOR_IDENTIFIER,
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,
#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]
/* 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) \
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) \
{"__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},
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
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);
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<tree, va_gc> *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;
}
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
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<tree, va_gc> *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. */
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);
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)
{
virtual_depth++;
/* First, locate the unhidden ones at this level. */
- vec<tree, va_gc> *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;