From 5655267ca161de13e553dbfc0b7e58962fbb2443 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 13 Apr 2016 16:11:20 -0400 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 9 +++++++++ gcc/cp/call.c | 49 +++++++++++++++++++++++++++++++++++++++++++----- gcc/cp/cp-tree.h | 3 +++ gcc/cp/decl.c | 4 ++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 837a58c338f1..28541bc7857e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2016-04-13 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. + 2016-04-13 Jason Merrill PR c++/70627 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index ed234904a63d..84b62436da3a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -214,6 +214,8 @@ static void add_candidates (tree, tree, const vec *, 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 a3cd834a1055..faea452531c6 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 380bc79ea532..5ca426bbd03c 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); -- 2.43.0