Commit 5655267c by Jason Merrill Committed by Jason Merrill

Pass empty class parameters like C.

	* call.c (pass_as_empty_struct, empty_class_arg): New.
	(type_passed_as, build_x_va_arg): Use pass_as_empty_struct.
	(build_call_a): Use empty_class_arg.
	* cp-tree.h (CPTI_EMPTY_STRUCT, empty_struct_type): New.
	* decl.c (cxx_init_decl_processing): Create empty_struct_type.

From-SVN: r234959
parent 88b5d499
2016-04-13 Jason Merrill <jason@redhat.com> 2016-04-13 Jason Merrill <jason@redhat.com>
Pass empty class parameters like C.
* call.c (pass_as_empty_struct, empty_class_arg): New.
(type_passed_as, build_x_va_arg): Use pass_as_empty_struct.
(build_call_a): Use empty_class_arg.
* cp-tree.h (CPTI_EMPTY_STRUCT, empty_struct_type): New.
* decl.c (cxx_init_decl_processing): Create empty_struct_type.
2016-04-13 Jason Merrill <jason@redhat.com>
PR c++/70627 PR c++/70627
* decl.c (start_enum): Don't change an existing ENUM_UNDERLYING_TYPE. * decl.c (start_enum): Don't change an existing ENUM_UNDERLYING_TYPE.
......
...@@ -214,6 +214,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree, ...@@ -214,6 +214,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
tsubst_flags_t); tsubst_flags_t);
static conversion *merge_conversion_sequences (conversion *, conversion *); static conversion *merge_conversion_sequences (conversion *, conversion *);
static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t); static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
static bool pass_as_empty_struct (tree type);
static tree empty_class_arg (tree);
/* Returns nonzero iff the destructor name specified in NAME matches BASETYPE. /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
NAME can take many forms... */ NAME can take many forms... */
...@@ -383,12 +385,11 @@ build_call_a (tree function, int n, tree *argarray) ...@@ -383,12 +385,11 @@ build_call_a (tree function, int n, tree *argarray)
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
tree arg = CALL_EXPR_ARG (function, i); tree arg = CALL_EXPR_ARG (function, i);
if (is_empty_class (TREE_TYPE (arg)) tree type = TREE_TYPE (arg);
&& ! TREE_ADDRESSABLE (TREE_TYPE (arg))) if (is_really_empty_class (type)
&& ! TREE_ADDRESSABLE (type))
{ {
tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg)); CALL_EXPR_ARG (function, i) = empty_class_arg (arg);
arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
CALL_EXPR_ARG (function, i) = arg;
} }
} }
...@@ -6872,6 +6873,14 @@ build_x_va_arg (source_location loc, tree expr, tree type) ...@@ -6872,6 +6873,14 @@ build_x_va_arg (source_location loc, tree expr, tree type)
expr = build_va_arg (loc, expr, ref); expr = build_va_arg (loc, expr, ref);
return convert_from_reference (expr); return convert_from_reference (expr);
} }
else if (is_really_empty_class (type) && !TREE_ADDRESSABLE (type))
{
/* Do the reverse of empty_class_arg. */
tree etype = pass_as_empty_struct (type) ? empty_struct_type : type;
expr = build_va_arg (loc, expr, etype);
tree ec = build0 (EMPTY_CLASS_EXPR, type);
return build2 (COMPOUND_EXPR, type, expr, ec);
}
return build_va_arg (loc, expr, type); return build_va_arg (loc, expr, type);
} }
...@@ -6968,6 +6977,34 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum, ...@@ -6968,6 +6977,34 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum,
return arg; return arg;
} }
/* Return true iff TYPE should be passed and returned as a size 0 type rather
than its normal size, for compatibility with C. */
static bool
pass_as_empty_struct (tree type)
{
return (abi_version_at_least (10)
&& type != error_mark_node
&& COMPLETE_TYPE_P (type)
&& !TREE_ADDRESSABLE (type)
&& is_really_empty_class (type));
}
/* Adjust the value VAL of empty class type TYPE for argument passing.
Keep this synced with build_x_va_arg. */
static tree
empty_class_arg (tree val)
{
/* Don't pass empty class objects by value. This is useful
for tags in STL, which are used to control overload resolution.
We don't need to handle other cases of copying empty classes. */
tree type = TREE_TYPE (val);
tree etype = pass_as_empty_struct (type) ? empty_struct_type : type;
tree empty = build0 (EMPTY_CLASS_EXPR, etype);
return build2 (COMPOUND_EXPR, etype, val, empty);
}
/* Returns the type which will really be used for passing an argument of /* Returns the type which will really be used for passing an argument of
type TYPE. */ type TYPE. */
...@@ -6986,6 +7023,8 @@ type_passed_as (tree type) ...@@ -6986,6 +7023,8 @@ type_passed_as (tree type)
&& COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (type)
&& tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node))) && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
type = integer_type_node; type = integer_type_node;
else if (pass_as_empty_struct (type))
type = empty_struct_type;
return type; return type;
} }
......
...@@ -1150,6 +1150,8 @@ enum cp_tree_index ...@@ -1150,6 +1150,8 @@ enum cp_tree_index
CPTI_NULLPTR, CPTI_NULLPTR,
CPTI_NULLPTR_TYPE, CPTI_NULLPTR_TYPE,
CPTI_EMPTY_STRUCT,
CPTI_MAX CPTI_MAX
}; };
...@@ -1185,6 +1187,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -1185,6 +1187,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define current_aggr cp_global_trees[CPTI_AGGR_TAG] #define current_aggr cp_global_trees[CPTI_AGGR_TAG]
#define nullptr_node cp_global_trees[CPTI_NULLPTR] #define nullptr_node cp_global_trees[CPTI_NULLPTR]
#define nullptr_type_node cp_global_trees[CPTI_NULLPTR_TYPE] #define nullptr_type_node cp_global_trees[CPTI_NULLPTR_TYPE]
#define empty_struct_type cp_global_trees[CPTI_EMPTY_STRUCT]
/* We cache these tree nodes so as to call get_identifier less /* We cache these tree nodes so as to call get_identifier less
frequently. */ frequently. */
......
...@@ -4180,6 +4180,10 @@ cxx_init_decl_processing (void) ...@@ -4180,6 +4180,10 @@ cxx_init_decl_processing (void)
nullptr_node = build_int_cst (nullptr_type_node, 0); nullptr_node = build_int_cst (nullptr_type_node, 0);
} }
empty_struct_type = make_node (RECORD_TYPE);
finish_builtin_struct (empty_struct_type, "__empty_struct",
NULL_TREE, NULL_TREE);
abort_fndecl abort_fndecl
= build_library_fn_ptr ("__cxa_pure_virtual", void_ftype, = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype,
ECF_NORETURN | ECF_NOTHROW); ECF_NORETURN | ECF_NOTHROW);
......
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