From d2f2e467c03f108a407473366c950bc2371ca00a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 13 Aug 2014 14:25:06 -0400 Subject: [PATCH] call.c (build_x_va_arg): Support passing non-POD through .... * call.c (build_x_va_arg): Support passing non-POD through .... (convert_arg_to_ellipsis): Likewise. From-SVN: r213921 --- gcc/cp/ChangeLog | 5 ++ gcc/cp/call.c | 48 ++++++++++++------- gcc/doc/implement-cxx.texi | 4 +- gcc/testsuite/g++.dg/ext/varargs1.C | 34 +++++++++++++ gcc/testsuite/g++.dg/overload/ellipsis1.C | 3 +- gcc/testsuite/g++.dg/overload/ellipsis2.C | 3 +- gcc/testsuite/g++.dg/warn/var-args1.C | 2 +- .../g++.old-deja/g++.brendan/crash63.C | 2 +- gcc/testsuite/g++.old-deja/g++.other/vaarg3.C | 15 +++--- gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C | 7 +-- 10 files changed, 90 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/varargs1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0889ea6e7fe..d4163b0682f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2014-08-13 Jason Merrill + + * call.c (build_x_va_arg): Support passing non-POD through .... + (convert_arg_to_ellipsis): Likewise. + 2014-08-13 Andrew Sutton * pt.c (lookup_template_variable): Make dependent variable templates diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 64cab453ae0..43bfe504d21 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -6570,8 +6570,8 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) with no corresponding parameter is conditionally-supported, with implementation-defined semantics. - We used to just warn here and do a bitwise copy, but now - cp_expr_size will abort if we try to do that. + We support it as pass-by-invisible-reference, just like a normal + value parameter. If the call appears in the context of a sizeof expression, it is not potentially-evaluated. */ @@ -6579,10 +6579,12 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain) && (type_has_nontrivial_copy_init (arg_type) || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type))) { - if (complain & tf_error) - error_at (loc, "cannot pass objects of non-trivially-copyable " - "type %q#T through %<...%>", arg_type); - return error_mark_node; + if (complain & tf_warning) + warning (OPT_Wconditionally_supported, + "passing objects of non-trivially-copyable " + "type %q#T through %<...%> is conditionally supported", + arg_type); + return cp_build_addr_expr (arg, complain); } } @@ -6595,7 +6597,11 @@ tree build_x_va_arg (source_location loc, tree expr, tree type) { if (processing_template_decl) - return build_min (VA_ARG_EXPR, type, expr); + { + tree r = build_min (VA_ARG_EXPR, type, expr); + SET_EXPR_LOCATION (r, loc); + return r; + } type = complete_type_or_else (type, NULL_TREE); @@ -6604,18 +6610,24 @@ build_x_va_arg (source_location loc, tree expr, tree type) expr = mark_lvalue_use (expr); + if (TREE_CODE (type) == REFERENCE_TYPE) + { + error ("cannot receive reference type %qT through %<...%>", type); + return error_mark_node; + } + if (type_has_nontrivial_copy_init (type) - || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) - || TREE_CODE (type) == REFERENCE_TYPE) - { - /* Remove reference types so we don't ICE later on. */ - tree type1 = non_reference (type); - /* conditionally-supported behavior [expr.call] 5.2.2/7. */ - error ("cannot receive objects of non-trivially-copyable type %q#T " - "through %<...%>; ", type); - expr = convert (build_pointer_type (type1), null_node); - expr = cp_build_indirect_ref (expr, RO_NULL, tf_warning_or_error); - return expr; + || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) + { + /* conditionally-supported behavior [expr.call] 5.2.2/7. Let's treat + it as pass by invisible reference. */ + warning_at (loc, OPT_Wconditionally_supported, + "receiving objects of non-trivially-copyable type %q#T " + "through %<...%> is conditionally-supported", type); + + tree ref = cp_build_reference_type (type, false); + expr = build_va_arg (loc, expr, ref); + return convert_from_reference (expr); } return build_va_arg (loc, expr, type); diff --git a/gcc/doc/implement-cxx.texi b/gcc/doc/implement-cxx.texi index 50efcc39b6d..58023119898 100644 --- a/gcc/doc/implement-cxx.texi +++ b/gcc/doc/implement-cxx.texi @@ -42,7 +42,9 @@ all conditionally-supported constructs that it does not support (C++0x @cite{Whether an argument of class type with a non-trivial copy constructor or destructor can be passed to ... (C++0x 5.2.2).} -Such argument passing is not supported. +Such argument passing is supported, using the same +pass-by-invisible-reference approach used for normal function +arguments of such types. @end itemize diff --git a/gcc/testsuite/g++.dg/ext/varargs1.C b/gcc/testsuite/g++.dg/ext/varargs1.C new file mode 100644 index 00000000000..b67d788e1b7 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/varargs1.C @@ -0,0 +1,34 @@ +// Test that passing an object with non-trivial copy constructor and +// destructor is (conditionally) supported and has sensible semantics. + +#include +extern "C" void abort(); + +void *as[5]; +int i; + +struct A { + A() { as[i++] = this; } + A(const A& a) { + if (&a != as[i-1]) + abort(); + as[i++] = this; + } + ~A() { + if (this != as[--i]) + abort(); + } +}; + +void f(int i, ...) { + va_list ap; + va_start (ap, i); + A ar = va_arg (ap, A); +} + +int main() +{ + f(42,A()); + if (i != 0) + abort(); +} diff --git a/gcc/testsuite/g++.dg/overload/ellipsis1.C b/gcc/testsuite/g++.dg/overload/ellipsis1.C index 3dedaa6be4a..1dde2bc1d2a 100644 --- a/gcc/testsuite/g++.dg/overload/ellipsis1.C +++ b/gcc/testsuite/g++.dg/overload/ellipsis1.C @@ -1,5 +1,6 @@ // PR c++/15142 // Bug: We were aborting after giving a warning about passing a non-POD. +// { dg-options "-Wconditionally-supported" } struct B { B() throw() { } @@ -14,5 +15,5 @@ struct X { struct S { S(...); }; void SillyFunc() { - throw S(X()); // { dg-error "copy" } + throw S(X()); // { dg-message "copy" } } diff --git a/gcc/testsuite/g++.dg/overload/ellipsis2.C b/gcc/testsuite/g++.dg/overload/ellipsis2.C index d9118ba643c..c226e1c5e58 100644 --- a/gcc/testsuite/g++.dg/overload/ellipsis2.C +++ b/gcc/testsuite/g++.dg/overload/ellipsis2.C @@ -1,4 +1,5 @@ // PR c++/60253 +// { dg-options "-Wconditionally-supported" } struct A { @@ -10,4 +11,4 @@ struct B B(...); }; -B b(0, A()); // { dg-error "cannot pass" } +B b(0, A()); // { dg-message "pass" } diff --git a/gcc/testsuite/g++.dg/warn/var-args1.C b/gcc/testsuite/g++.dg/warn/var-args1.C index 9bd84a7dd55..35deb096a65 100644 --- a/gcc/testsuite/g++.dg/warn/var-args1.C +++ b/gcc/testsuite/g++.dg/warn/var-args1.C @@ -6,6 +6,6 @@ void foo(int, ...) { va_list va; int i; - i = va_arg(va, int&); /* { dg-error "cannot receive objects" } */ + i = va_arg(va, int&); /* { dg-error "cannot receive" } */ } diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash63.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash63.C index 89685fcaeb5..badd926c241 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/crash63.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash63.C @@ -13,4 +13,4 @@ class UnitList UnitList (...); }; -UnitList unit_list (String("keV")); // { dg-error "" } cannot pass non-pod +UnitList unit_list (String("keV")); diff --git a/gcc/testsuite/g++.old-deja/g++.other/vaarg3.C b/gcc/testsuite/g++.old-deja/g++.other/vaarg3.C index 134a89c97f6..98f78773750 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/vaarg3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/vaarg3.C @@ -1,5 +1,6 @@ // { dg-do assemble } -// { dg-options "-Wno-abi" { target arm_eabi } } +// { dg-options "-Wconditionally-supported" } +// { dg-options "-Wno-abi -Wconditionally-supported" { target arm_eabi } } // Copyright (C) 1999 Free Software Foundation, Inc. // Contributed by Nathan Sidwell 4 Oct 1999 @@ -14,19 +15,19 @@ struct Z; // { dg-message "forward decl" } void fn1(va_list args) { int i = va_arg (args, int); - Y x = va_arg (args, Y); // { dg-error "cannot receive" } - Y y = va_arg (args, struct Y); // { dg-error "cannot receive" } + Y x = va_arg (args, Y); // { dg-message "receiv" } + Y y = va_arg (args, struct Y); // { dg-message "receiv" } int &r = va_arg (args, int &); // { dg-error "cannot receive" } Z z1 = va_arg (args, Z); // { dg-error "incomplete" } const Z &z2 = va_arg (args, Z); // { dg-error "incomplete" } va_arg (args, char); // { dg-warning "promote" } - // { dg-message "should pass" "pass" { target *-*-* } 24 } - // { dg-message "abort" "abort" { target *-*-* } 24 } + // { dg-message "should pass" "pass" { target *-*-* } 25 } + // { dg-message "abort" "abort" { target *-*-* } 25 } va_arg (args, int []); // { dg-error "array with unspecified bounds" } promote va_arg (args, int ()); // { dg-warning "promoted" } promote - // { dg-message "abort" "abort" { target *-*-* } 28 } + // { dg-message "abort" "abort" { target *-*-* } 29 } va_arg (args, bool); // { dg-warning "promote" "promote" } - // { dg-message "abort" "abort" { target *-*-* } 30 } + // { dg-message "abort" "abort" { target *-*-* } 31 } } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C b/gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C index e8801194283..ee84db9b805 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/vaarg3.C @@ -1,4 +1,5 @@ // { dg-do assemble } +// { dg-options "-Wconditionally-supported" } // Copyright (C) 2000 Free Software Foundation // Contributed by Nathan Sidwell 22 June 2000 @@ -14,14 +15,14 @@ void PrintArgs (Type somearg, ...) va_list argp; va_start (argp, somearg); Type value; -value = va_arg (argp, Type); // { dg-error "cannot receive" } cannot pass non-POD +value = va_arg (argp, Type); // { dg-message "receiv" } cannot pass non-POD va_end (argp); } int main (void) { A dummy; -PrintArgs (dummy, dummy); // { dg-error "cannot pass" } cannot pass non-POD -// { dg-message "required" "inst" { target *-*-* } 24 } +PrintArgs (dummy, dummy); // { dg-message "pass" } cannot pass non-POD +// { dg-message "required" "inst" { target *-*-* } 25 } return 0; } -- 2.30.2