summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-13 20:11:20 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-13 20:11:20 +0000
commit9d81feb8813a8790504fb608bd9e50b5543879ee (patch)
treee3b6ab9a03bc4e6ddada960bd1a94788283c70ad
parent22f82b652e877c7ff574c23e586c46eef0fdb500 (diff)
downloadgcc-9d81feb8813a8790504fb608bd9e50b5543879ee.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@234959 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog9
-rw-r--r--gcc/cp/call.c49
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c4
4 files changed, 60 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 837a58c338f..28541bc7857 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,14 @@
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
* decl.c (start_enum): Don't change an existing ENUM_UNDERLYING_TYPE.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ed234904a63..84b62436da3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -214,6 +214,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
tsubst_flags_t);
static conversion *merge_conversion_sequences (conversion *, conversion *);
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.
NAME can take many forms... */
@@ -383,12 +385,11 @@ build_call_a (tree function, int n, tree *argarray)
for (i = 0; i < n; i++)
{
tree arg = CALL_EXPR_ARG (function, i);
- if (is_empty_class (TREE_TYPE (arg))
- && ! TREE_ADDRESSABLE (TREE_TYPE (arg)))
+ tree type = TREE_TYPE (arg);
+ if (is_really_empty_class (type)
+ && ! TREE_ADDRESSABLE (type))
{
- tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
- arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
- CALL_EXPR_ARG (function, i) = arg;
+ CALL_EXPR_ARG (function, i) = empty_class_arg (arg);
}
}
@@ -6872,6 +6873,14 @@ build_x_va_arg (source_location loc, tree expr, tree type)
expr = build_va_arg (loc, expr, ref);
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);
}
@@ -6968,6 +6977,34 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum,
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
type TYPE. */
@@ -6986,6 +7023,8 @@ type_passed_as (tree type)
&& COMPLETE_TYPE_P (type)
&& tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
type = integer_type_node;
+ else if (pass_as_empty_struct (type))
+ type = empty_struct_type;
return type;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a3cd834a105..faea452531c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1150,6 +1150,8 @@ enum cp_tree_index
CPTI_NULLPTR,
CPTI_NULLPTR_TYPE,
+ CPTI_EMPTY_STRUCT,
+
CPTI_MAX
};
@@ -1185,6 +1187,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define current_aggr cp_global_trees[CPTI_AGGR_TAG]
#define nullptr_node cp_global_trees[CPTI_NULLPTR]
#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
frequently. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 380bc79ea53..5ca426bbd03 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4180,6 +4180,10 @@ cxx_init_decl_processing (void)
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
= build_library_fn_ptr ("__cxa_pure_virtual", void_ftype,
ECF_NORETURN | ECF_NOTHROW);