aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2017-08-25 11:37:10 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2017-08-25 11:37:10 +0000
commitbff8b385e997a85cce62031c80bac1b431659fcd (patch)
treef02f660066158abece2226c1baa96e2f8c16f826 /gcc/cp
parent6512c0f187d84dd046380aa53673dc5ae20795e3 (diff)
downloadgcc-bff8b385e997a85cce62031c80bac1b431659fcd.zip
gcc-bff8b385e997a85cce62031c80bac1b431659fcd.tar.gz
gcc-bff8b385e997a85cce62031c80bac1b431659fcd.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog21
-rw-r--r--gcc/cp/class.c101
-rw-r--r--gcc/cp/cp-tree.h11
-rw-r--r--gcc/cp/decl.c8
-rw-r--r--gcc/cp/decl2.c2
-rw-r--r--gcc/cp/name-lookup.c112
-rw-r--r--gcc/cp/name-lookup.h1
-rw-r--r--gcc/cp/pt.c17
-rw-r--r--gcc/cp/search.c8
9 files changed, 132 insertions, 149 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 92ecf91..3557e48 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,24 @@
+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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a08ce89..fc37bd8 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<tree, va_gc> *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<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);
}
}
@@ -2323,15 +2325,10 @@ resort_type_method_vec (void* obj,
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))
@@ -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<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;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b915bd9..d04c00c 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 a9d72c0..bd6926a 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 66d206e..0f828b5 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 3d69e1d..df29331 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<tree, va_gc> *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<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;
}
@@ -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<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. */
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 1f67147..99f9b9b 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<tree, va_gc> *);
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 8d816c7..564ffb0 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 31f4dd6..266d8dd 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<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;