Commit d6dd9d7f by Nathan Sidwell Committed by Nathan Sidwell

[C++ PATCH] overloaded operator fns [6/N]

https://gcc.gnu.org/ml/gcc-patches/2017-11/msg00018.html
	* cp-tree.h (IDENTIFIER_CP_INDEX): Define.
	(enum ovl_op_flags): Add OVL_OP_FLAG_AMBIARY.
	(enum ovl_op_code): New.
	(struct ovl_op_info): Add ovl_op_code field.
	(ovl_op_info): Size by OVL_OP_MAX.
	(ovl_op_mapping, ovl_op_alternate): Declare.
	(OVL_OP_INFO): Adjust for mapping array.
	(IDENTIFIER_OVL_OP_INFO): New.
	* decl.c (ambi_op_p, unary_op_p): Delete.
	(grok_op_properties): Use IDENTIFIER_OVL_OP_INFO and
	ovl_op_alternate.
	* lex.c (ovl_op_info): Adjust and static initialize.
	(ovl_op_mappings, ovl_op_alternate): Define.
	(init_operators): Iterate over ovl_op_info array and init mappings
	& alternate arrays.
	* mangle.c (write_unqualified_id): Use IDENTIFIER_OVL_OP_INFO.
	* operators.def (DEF_OPERATOR): Remove KIND parm.
	(DEF_SIMPLE_OPERATOR): Delete.
	(OPERATOR_TRANSITION): Expand if defined.

From-SVN: r254310
parent 0299d48b
2017-11-01 Nathan Sidwell <nathan@acm.org>
* cp-tree.h (IDENTIFIER_CP_INDEX): Define.
(enum ovl_op_flags): Add OVL_OP_FLAG_AMBIARY.
(enum ovl_op_code): New.
(struct ovl_op_info): Add ovl_op_code field.
(ovl_op_info): Size by OVL_OP_MAX.
(ovl_op_mapping, ovl_op_alternate): Declare.
(OVL_OP_INFO): Adjust for mapping array.
(IDENTIFIER_OVL_OP_INFO): New.
* decl.c (ambi_op_p, unary_op_p): Delete.
(grok_op_properties): Use IDENTIFIER_OVL_OP_INFO and
ovl_op_alternate.
* lex.c (ovl_op_info): Adjust and static initialize.
(ovl_op_mappings, ovl_op_alternate): Define.
(init_operators): Iterate over ovl_op_info array and init mappings
& alternate arrays.
* mangle.c (write_unqualified_id): Use IDENTIFIER_OVL_OP_INFO.
* operators.def (DEF_OPERATOR): Remove KIND parm.
(DEF_SIMPLE_OPERATOR): Delete.
(OPERATOR_TRANSITION): Expand if defined.
2017-10-31 David Malcolm <dmalcolm@redhat.com>
* pt.c (listify): Use %< and %> for description of #include.
......
......@@ -1072,6 +1072,11 @@ enum cp_identifier_kind {
& IDENTIFIER_KIND_BIT_1 (NODE) \
& IDENTIFIER_KIND_BIT_0 (NODE))
/* Access a C++-specific index for identifier NODE.
Used to optimize operator mappings etc. */
#define IDENTIFIER_CP_INDEX(NODE) \
(IDENTIFIER_NODE_CHECK(NODE)->base.u.bits.address_space)
/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only. */
#define C_TYPE_FIELDS_READONLY(TYPE) \
(LANG_TYPE_CLASS_CHECK (TYPE)->fields_readonly)
......@@ -5477,12 +5482,25 @@ extern void init_reswords (void);
/* Various flags for the overloaded operator information. */
enum ovl_op_flags
{
OVL_OP_FLAG_NONE = 0,
OVL_OP_FLAG_UNARY = 1,
OVL_OP_FLAG_BINARY = 2,
OVL_OP_FLAG_ALLOC = 4, /* operator new or delete */
OVL_OP_FLAG_DELETE = 1, /* operator delete */
OVL_OP_FLAG_VEC = 2 /* vector new or delete */
OVL_OP_FLAG_NONE = 0, /* Don't care. */
OVL_OP_FLAG_UNARY = 1, /* Is unary. */
OVL_OP_FLAG_BINARY = 2, /* Is binary. */
OVL_OP_FLAG_AMBIARY = 3, /* May be unary or binary. */
OVL_OP_FLAG_ALLOC = 4, /* operator new or delete. */
OVL_OP_FLAG_DELETE = 1, /* operator delete. */
OVL_OP_FLAG_VEC = 2 /* vector new or delete. */
};
/* Compressed operator codes. Order is determined by operators.def
and does not match that of tree_codes. */
enum ovl_op_code
{
OVL_OP_ERROR_MARK,
OVL_OP_NOP_EXPR,
#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) OVL_OP_##CODE,
#define DEF_ASSN_OPERATOR(NAME, CODE, MANGLING) /* NOTHING */
#include "operators.def"
OVL_OP_MAX
};
struct GTY(()) ovl_op_info_t {
......@@ -5492,19 +5510,29 @@ struct GTY(()) ovl_op_info_t {
const char *name;
/* The mangled name of the operator. */
const char *mangled_name;
/* The tree code. */
/* The (regular) tree code. */
enum tree_code tree_code : 16;
/* The (compressed) operator code. */
enum ovl_op_code ovl_op_code : 8;
/* The ovl_op_flags of the operator */
unsigned flags : 8;
};
/* Overloaded operator info indexed by ass_op_p & tree_code. */
extern GTY(()) ovl_op_info_t ovl_op_info[2][MAX_TREE_CODES];
/* Overloaded operator info indexed by ass_op_p & ovl_op_code. */
extern GTY(()) ovl_op_info_t ovl_op_info[2][OVL_OP_MAX];
/* Mapping from tree_codes to ovl_op_codes. */
extern GTY(()) unsigned char ovl_op_mapping[MAX_TREE_CODES];
/* Mapping for ambi-ary operators from the binary to the unary. */
extern GTY(()) unsigned char ovl_op_alternate[OVL_OP_MAX];
/* Given an ass_op_p boolean and a tree code, return a pointer to its
overloaded operator info. */
#define OVL_OP_INFO(IS_ASS_P, TREE_CODE) \
(&ovl_op_info[(IS_ASS_P) != 0][(TREE_CODE)])
(&ovl_op_info[(IS_ASS_P) != 0][ovl_op_mapping[(TREE_CODE)]])
/* Overloaded operator info for an identifier for which
IDENTIFIER_ANY_OP_P is true. */
#define IDENTIFIER_OVL_OP_INFO(NODE) \
(&ovl_op_info[IDENTIFIER_ASSIGN_OP_P (NODE)][IDENTIFIER_CP_INDEX (NODE)])
/* A type-qualifier, or bitmask therefore, using the TYPE_QUAL
constants. */
......
......@@ -65,8 +65,6 @@ static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
static void require_complete_types_for_parms (tree);
static bool ambi_op_p (enum tree_code);
static bool unary_op_p (enum tree_code);
static void push_local_name (tree);
static tree grok_reference_init (tree, tree, tree, int);
static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
......@@ -12874,30 +12872,6 @@ grok_ctor_properties (const_tree ctype, const_tree decl)
return true;
}
/* An operator with this code is unary, but can also be binary. */
static bool
ambi_op_p (enum tree_code code)
{
return (code == INDIRECT_REF
|| code == ADDR_EXPR
|| code == UNARY_PLUS_EXPR
|| code == NEGATE_EXPR
|| code == PREINCREMENT_EXPR
|| code == PREDECREMENT_EXPR);
}
/* An operator with this name can only be unary. */
static bool
unary_op_p (enum tree_code code)
{
return (code == TRUTH_NOT_EXPR
|| code == BIT_NOT_EXPR
|| code == COMPONENT_REF
|| code == TYPE_EXPR);
}
/* DECL is a declaration for an overloaded or conversion operator. If
COMPLAIN is true, errors are issued for invalid declarations. */
......@@ -12905,15 +12879,15 @@ bool
grok_op_properties (tree decl, bool complain)
{
tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
int methodp = (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
bool methodp = TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE;
tree name = DECL_NAME (decl);
tree class_type = DECL_CONTEXT (decl);
if (class_type && !CLASS_TYPE_P (class_type))
class_type = NULL_TREE;
tree_code operator_code = ERROR_MARK;
unsigned op_flags = OVL_OP_FLAG_NONE;
tree_code operator_code;
unsigned op_flags;
if (IDENTIFIER_CONV_OP_P (name))
{
/* Conversion operators are TYPE_EXPR for the purposes of this
......@@ -12923,21 +12897,11 @@ grok_op_properties (tree decl, bool complain)
}
else
{
/* It'd be nice to hang something else of the identifier to
find CODE more directly. */
bool assign_op = IDENTIFIER_ASSIGN_OP_P (name);
const ovl_op_info_t *ovl_op = OVL_OP_INFO (assign_op, 0);
if (false)
;
#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, KIND) \
else if (ovl_op[CODE].identifier == name) \
operator_code = (CODE);
#include "operators.def"
#undef DEF_OPERATOR
else
gcc_unreachable ();
gcc_assert (operator_code != ERROR_MARK);
op_flags = ovl_op[operator_code].flags;
const ovl_op_info_t *ovl_op = IDENTIFIER_OVL_OP_INFO (name);
operator_code = ovl_op->tree_code;
op_flags = ovl_op->flags;
gcc_checking_assert (operator_code != ERROR_MARK);
DECL_OVERLOADED_OPERATOR_CODE (decl) = operator_code;
}
......@@ -13071,70 +13035,43 @@ grok_op_properties (tree decl, bool complain)
}
/* Verify correct number of arguments. */
if (ambi_op_p (operator_code))
switch (op_flags)
{
case OVL_OP_FLAG_AMBIARY:
if (arity == 1)
/* We pick the one-argument operator codes by default, so
we don't have to change anything. */
;
else if (arity == 2)
{
/* If we thought this was a unary operator, we now know
it to be a binary operator. */
switch (operator_code)
{
case INDIRECT_REF:
operator_code = MULT_EXPR;
break;
case ADDR_EXPR:
operator_code = BIT_AND_EXPR;
break;
case UNARY_PLUS_EXPR:
operator_code = PLUS_EXPR;
break;
case NEGATE_EXPR:
operator_code = MINUS_EXPR;
break;
case PREINCREMENT_EXPR:
operator_code = POSTINCREMENT_EXPR;
break;
case PREDECREMENT_EXPR:
operator_code = POSTDECREMENT_EXPR;
break;
default:
gcc_unreachable ();
}
/* We have a unary instance of an ambi-ary op. Remap to the
unary one. */
unsigned alt = ovl_op_alternate[ovl_op_mapping [operator_code]];
const ovl_op_info_t *ovl_op = &ovl_op_info[false][alt];
gcc_checking_assert (ovl_op->flags == OVL_OP_FLAG_UNARY);
operator_code = ovl_op->tree_code;
DECL_OVERLOADED_OPERATOR_CODE (decl) = operator_code;
if ((operator_code == POSTINCREMENT_EXPR
|| operator_code == POSTDECREMENT_EXPR)
&& ! processing_template_decl
&& ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)), integer_type_node))
{
error (methodp
? G_("postfix %qD must have %<int%> as its argument")
: G_("postfix %qD must have %<int%> as its second argument"),
decl);
return false;
}
}
else
else if (arity != 2)
{
/* This was an ambiguous operator but is invalid. */
error (methodp
? G_("%qD must have either zero or one argument")
: G_("%qD must have either one or two arguments"), decl);
return false;
}
}
else if (unary_op_p (operator_code))
{
else if ((operator_code == POSTINCREMENT_EXPR
|| operator_code == POSTDECREMENT_EXPR)
&& ! processing_template_decl
/* x++ and x--'s second argument must be an int. */
&& ! same_type_p (TREE_VALUE (TREE_CHAIN (argtypes)),
integer_type_node))
{
error (methodp
? G_("postfix %qD must have %<int%> as its argument")
: G_("postfix %qD must have %<int%> as its second argument"),
decl);
return false;
}
break;
case OVL_OP_FLAG_UNARY:
if (arity != 1)
{
error (methodp
......@@ -13142,9 +13079,9 @@ grok_op_properties (tree decl, bool complain)
: G_("%qD must have exactly one argument"), decl);
return false;
}
}
else
{
break;
case OVL_OP_FLAG_BINARY:
if (arity != 2)
{
error (methodp
......@@ -13152,8 +13089,12 @@ grok_op_properties (tree decl, bool complain)
: G_("%qD must have exactly two arguments"), decl);
return false;
}
break;
default:
gcc_unreachable ();
}
/* There can be no default arguments. */
for (tree arg = argtypes; arg != void_list_node; arg = TREE_CHAIN (arg))
if (TREE_PURPOSE (arg))
......
......@@ -77,7 +77,20 @@ cxx_finish (void)
c_common_finish ();
}
ovl_op_info_t ovl_op_info[2][MAX_TREE_CODES];
ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
{
{
{NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
{NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
{NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
#define OPERATOR_TRANSITION }, { \
{NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
#include "operators.def"
}
};
unsigned char ovl_op_mapping[MAX_TREE_CODES];
unsigned char ovl_op_alternate[OVL_OP_MAX];
/* Get the name of the kind of identifier T. */
......@@ -129,26 +142,77 @@ set_operator_ident (ovl_op_info_t *ptr)
return ident;
}
/* Initialize data structures that keep track of operator names. */
static void
init_operators (void)
{
tree identifier;
ovl_op_info_t *oni;
#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS, KIND) \
oni = OVL_OP_INFO (KIND == cik_assign_op, CODE); \
oni->name = NAME; \
oni->mangled_name = MANGLING; \
oni->tree_code = CODE; \
oni->flags = FLAGS; \
if (NAME) { \
identifier = set_operator_ident (oni); \
if (KIND != cik_simple_op || !IDENTIFIER_ANY_OP_P (identifier)) \
set_identifier_kind (identifier, KIND); \
}
/* We rely on both these being zero. */
gcc_checking_assert (!OVL_OP_ERROR_MARK && !ERROR_MARK);
#include "operators.def"
#undef DEF_OPERATOR
/* This loop iterates backwards because we need to move the
assignment operators down to their correct slots. I.e. morally
equivalent to an overlapping memmove where dest > src. Slot
zero is for error_mark, so hae no operator. */
for (unsigned ix = OVL_OP_MAX; --ix;)
{
ovl_op_info_t *op_ptr = &ovl_op_info[false][ix];
if (op_ptr->name)
{
/* Make sure it fits in lang_decl_fn::operator_code. */
gcc_checking_assert (op_ptr->ovl_op_code < (1 << 6));
tree ident = set_operator_ident (op_ptr);
if (unsigned index = IDENTIFIER_CP_INDEX (ident))
{
ovl_op_info_t *bin_ptr = &ovl_op_info[false][index];
/* They should only differ in unary/binary ness. */
gcc_checking_assert ((op_ptr->flags ^ bin_ptr->flags)
== OVL_OP_FLAG_AMBIARY);
bin_ptr->flags |= op_ptr->flags;
ovl_op_alternate[index] = ix;
}
else
{
IDENTIFIER_CP_INDEX (ident) = ix;
set_identifier_kind (ident,
op_ptr->flags & OVL_OP_FLAG_ALLOC
? cik_newdel_op : cik_simple_op);
}
}
if (op_ptr->tree_code)
{
gcc_checking_assert (op_ptr->ovl_op_code == ix
&& !ovl_op_mapping[op_ptr->tree_code]);
ovl_op_mapping[op_ptr->tree_code] = op_ptr->ovl_op_code;
}
ovl_op_info_t *as_ptr = &ovl_op_info[true][ix];
if (as_ptr->name)
{
/* These will be placed at the start of the array, move to
the correct slot and initialize. */
if (as_ptr->ovl_op_code != ix)
{
ovl_op_info_t *dst_ptr = &ovl_op_info[true][as_ptr->ovl_op_code];
gcc_assert (as_ptr->ovl_op_code > ix && !dst_ptr->tree_code);
memcpy (dst_ptr, as_ptr, sizeof (*dst_ptr));
memset (as_ptr, 0, sizeof (*as_ptr));
as_ptr = dst_ptr;
}
tree ident = set_operator_ident (as_ptr);
gcc_checking_assert (!IDENTIFIER_CP_INDEX (ident));
IDENTIFIER_CP_INDEX (ident) = as_ptr->ovl_op_code;
set_identifier_kind (ident, cik_assign_op);
gcc_checking_assert (!ovl_op_mapping[as_ptr->tree_code]
|| (ovl_op_mapping[as_ptr->tree_code]
== as_ptr->ovl_op_code));
ovl_op_mapping[as_ptr->tree_code] = as_ptr->ovl_op_code;
}
}
}
/* Initialize the reserved words. */
......
......@@ -1265,30 +1265,8 @@ write_unqualified_id (tree identifier)
write_conversion_operator_name (TREE_TYPE (identifier));
else if (IDENTIFIER_ANY_OP_P (identifier))
{
const char *mangled_name = NULL;
bool assop = IDENTIFIER_ASSIGN_OP_P (identifier);
/* Unfortunately, there is no easy way to go from the
name of the operator back to the corresponding tree
code. */
for (unsigned i = 0; i < MAX_TREE_CODES; ++i)
{
const ovl_op_info_t *ovl_op = OVL_OP_INFO (assop, i);
if (ovl_op->identifier == identifier)
{
/* The ABI says that we prefer binary operator
names to unary operator names. */
if (ovl_op->flags == OVL_OP_FLAG_BINARY)
{
mangled_name = ovl_op->mangled_name;
break;
}
else if (!mangled_name)
mangled_name = ovl_op->mangled_name;
}
}
write_string (mangled_name);
const ovl_op_info_t *ovl_op = IDENTIFIER_OVL_OP_INFO (identifier);
write_string (ovl_op->mangled_name);
}
else if (UDLIT_OPER_P (identifier))
write_literal_operator_name (identifier);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment