+2014-08-13 Jason Merrill <jason@redhat.com>
+
+ * call.c (build_x_va_arg): Support passing non-POD through ....
+ (convert_arg_to_ellipsis): Likewise.
+
2014-08-13 Andrew Sutton <andrew.n.sutton@gmail.com>
* pt.c (lookup_template_variable): Make dependent variable templates
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. */
&& (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);
}
}
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);
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);
@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
--- /dev/null
+// Test that passing an object with non-trivial copy constructor and
+// destructor is (conditionally) supported and has sensible semantics.
+
+#include <stdarg.h>
+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();
+}
// PR c++/15142
// Bug: We were aborting after giving a warning about passing a non-POD.
+// { dg-options "-Wconditionally-supported" }
struct B {
B() throw() { }
struct S { S(...); };
void SillyFunc() {
- throw S(X()); // { dg-error "copy" }
+ throw S(X()); // { dg-message "copy" }
}
// PR c++/60253
+// { dg-options "-Wconditionally-supported" }
struct A
{
B(...);
};
-B b(0, A()); // { dg-error "cannot pass" }
+B b(0, A()); // { dg-message "pass" }
{
va_list va;
int i;
- i = va_arg(va, int&); /* { dg-error "cannot receive objects" } */
+ i = va_arg(va, int&); /* { dg-error "cannot receive" } */
}
UnitList (...);
};
-UnitList unit_list (String("keV")); // { dg-error "" } cannot pass non-pod
+UnitList unit_list (String("keV"));
// { 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 <nathan@acm.org>
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 }
}
// { dg-do assemble }
+// { dg-options "-Wconditionally-supported" }
// Copyright (C) 2000 Free Software Foundation
// Contributed by Nathan Sidwell 22 June 2000 <nathan@codesourcery.com>
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;
}