2019-12-03 Marek Polacek <pola...@redhat.com>
PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
* c-cppbuiltin.c (c_cpp_builtins): Predefine
__cpp_aggregate_paren_init=201902 for -std=c++2a.
* call.c (build_new_method_call_1): Handle parenthesized initialization
of aggregates by building up a CONSTRUCTOR.
(extend_ref_init_temps): Do nothing for CONSTRUCTOR_IS_PAREN_INIT.
* cp-tree.h (CONSTRUCTOR_IS_PAREN_INIT, LOOKUP_AGGREGATE_PAREN_INIT):
Define.
* decl.c (grok_reference_init): Handle aggregate initialization from
a parenthesized list of values.
(reshape_init): Do nothing for CONSTRUCTOR_IS_PAREN_INIT.
(check_initializer): Handle initialization of an array from a
parenthesized list of values. Use NULL_TREE instead of NULL.
* tree.c (build_cplus_new): Handle BRACE_ENCLOSED_INITIALIZER_P.
* typeck2.c (digest_init_r): Set LOOKUP_AGGREGATE_PAREN_INIT if it
receives a CONSTRUCTOR with CONSTRUCTOR_IS_PAREN_INIT set. Allow
narrowing when LOOKUP_AGGREGATE_PAREN_INIT.
(massage_init_elt): Don't lose LOOKUP_AGGREGATE_PAREN_INIT when passing
flags to digest_init_r.
* g++.dg/cpp0x/constexpr-99.C: Only expect an error in C++17 and
lesser.
* g++.dg/cpp0x/explicit7.C: Likewise.
* g++.dg/cpp0x/initlist12.C: Adjust dg-error.
* g++.dg/cpp0x/pr31437.C: Likewise.
* g++.dg/cpp2a/feat-cxx2a.C: Add __cpp_aggregate_paren_init test.
* g++.dg/cpp2a/paren-init1.C: New test.
* g++.dg/cpp2a/paren-init10.C: New test.
* g++.dg/cpp2a/paren-init11.C: New test.
* g++.dg/cpp2a/paren-init12.C: New test.
* g++.dg/cpp2a/paren-init13.C: New test.
* g++.dg/cpp2a/paren-init14.C: New test.
* g++.dg/cpp2a/paren-init15.C: New test.
* g++.dg/cpp2a/paren-init16.C: New test.
* g++.dg/cpp2a/paren-init17.C: New test.
* g++.dg/cpp2a/paren-init18.C: New test.
* g++.dg/cpp2a/paren-init19.C: New test.
* g++.dg/cpp2a/paren-init2.C: New test.
* g++.dg/cpp2a/paren-init3.C: New test.
* g++.dg/cpp2a/paren-init4.C: New test.
* g++.dg/cpp2a/paren-init5.C: New test.
* g++.dg/cpp2a/paren-init6.C: New test.
* g++.dg/cpp2a/paren-init7.C: New test.
* g++.dg/cpp2a/paren-init8.C: New test.
* g++.dg/cpp2a/paren-init9.C: New test.
* g++.dg/ext/desig10.C: Adjust dg-error.
* g++.dg/template/crash107.C: Likewise.
* g++.dg/template/crash95.C: Likewise.
* g++.old-deja/g++.jason/crash3.C: Likewise.
* g++.old-deja/g++.law/ctors11.C: Likewise.
* g++.old-deja/g++.law/ctors9.C: Likewise.
* g++.old-deja/g++.mike/net22.C: Likewise.
* g++.old-deja/g++.niklas/t128.C: Likewise.
diff --git gcc/c-family/c-cppbuiltin.c gcc/c-family/c-cppbuiltin.c
index 6491545bc3b..c7f4659456a 100644
--- gcc/c-family/c-cppbuiltin.c
+++ gcc/c-family/c-cppbuiltin.c
@@ -1006,6 +1006,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_impl_destroying_delete=201806L");
cpp_define (pfile, "__cpp_constexpr_dynamic_alloc=201907L");
cpp_define (pfile, "__cpp_impl_three_way_comparison=201907L");
+ cpp_define (pfile, "__cpp_aggregate_paren_init=201902L");
}
if (flag_concepts)
{
diff --git gcc/cp/call.c gcc/cp/call.c
index 062cff4c735..ea0e8b7e7d7 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -10124,6 +10124,38 @@ build_new_method_call_1 (tree instance, tree fns,
vec<tree, va_gc> **args,
if (!any_viable_p)
{
+ /* [dcl.init], 17.6.2.2:
+
+ Otherwise, if no constructor is viable, the destination type is
+ a (possibly cv-qualified) aggregate class A, and the initializer
+ is a parenthesized expression-list, the object is initialized as
+ follows...
+
+ We achieve this by building up a CONSTRUCTOR, as for list-init,
+ and setting CONSTRUCTOR_IS_PAREN_INIT to distinguish between
+ the two. */
+ if (DECL_CONSTRUCTOR_P (fn)
+ && !(flags & LOOKUP_ONLYCONVERTING)
+ && !cp_unevaluated_operand
+ && cxx_dialect >= cxx2a
+ && CP_AGGREGATE_TYPE_P (basetype)
+ && !user_args->is_empty ())
+ {
+ /* Create a CONSTRUCTOR from ARGS, e.g. {1, 2} from <1, 2>. */
+ tree list = build_tree_list_vec (user_args);
+ tree ctor = build_constructor_from_list (init_list_type_node, list);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
+ if (is_dummy_object (instance))
+ return ctor;
+ else
+ {
+ ctor = digest_init (basetype, ctor, complain);
+ ctor = build2 (INIT_EXPR, TREE_TYPE (instance), instance, ctor);
+ TREE_SIDE_EFFECTS (ctor) = true;
+ return ctor;
+ }
+ }
if (complain & tf_error)
complain_about_no_candidates_for_method_call (instance, candidates,
explicit_targs, basetype,
@@ -11789,9 +11821,16 @@ perform_direct_initialization_if_possible (tree type,
If the destination type is a (possibly cv-qualified) class type:
-- If the initialization is direct-initialization ...,
- constructors are considered. ... If no constructor applies, or
- the overload resolution is ambiguous, the initialization is
- ill-formed. */
+ constructors are considered.
+
+ -- If overload resolution is successful, the selected constructor
+ is called to initialize the object, with the initializer expression
+ or expression-list as its argument(s).
+
+ -- Otherwise, if no constructor is viable, the destination type is
+ a (possibly cv-qualified) aggregate class A, and the initializer is
+ a parenthesized expression-list, the object is initialized as
+ follows... */
if (CLASS_TYPE_P (type))
{
releasing_vec args (make_tree_vector_single (expr));
@@ -12147,6 +12186,12 @@ extend_ref_init_temps (tree decl, tree init, vec<tree,
va_gc> **cleanups)
ctor = TARGET_EXPR_INITIAL (ctor);
if (TREE_CODE (ctor) == CONSTRUCTOR)
{
+ /* [dcl.init] When initializing an aggregate from a parenthesized list
+ of values... a temporary object bound to a reference does not have
+ its lifetime extended. */
+ if (CONSTRUCTOR_IS_PAREN_INIT (ctor))
+ return init;
+
if (is_std_init_list (type))
{
/* The temporary array underlying a std::initializer_list
diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h
index 7e810b8ee7b..4af18b0ae62 100644
--- gcc/cp/cp-tree.h
+++ gcc/cp/cp-tree.h
@@ -4325,6 +4325,11 @@ more_aggr_init_expr_args_p (const
aggr_init_expr_arg_iterator *iter)
#define CONSTRUCTOR_IS_DESIGNATED_INIT(NODE) \
(TREE_LANG_FLAG_6 (CONSTRUCTOR_CHECK (NODE)))
+/* True if this CONSTRUCTOR comes from a parenthesized list of values, e.g.
+ A(1, 2, 3). */
+#define CONSTRUCTOR_IS_PAREN_INIT(NODE) \
+ (CONSTRUCTOR_CHECK(NODE)->base.private_flag)
+
/* True if NODE represents a conversion for direct-initialization in a
template. Set by perform_implicit_conversion_flags. */
#define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \
@@ -5583,6 +5588,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG,
TYPENAME_FLAG };
args), then we swap the conversions back in build_new_op_1 (so they
correspond to the order of the args in the candidate). */
#define LOOKUP_REVERSED (LOOKUP_REWRITTEN << 1)
+/* We're initializing an aggregate from a parenthesized list of values. */
+#define LOOKUP_AGGREGATE_PAREN_INIT (LOOKUP_REVERSED << 1)
#define LOOKUP_NAMESPACES_ONLY(F) \
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 81d73433547..54f09507516 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -5531,11 +5531,28 @@ grok_reference_init (tree decl, tree type, tree init,
int flags)
return NULL_TREE;
}
+ tree ttype = TREE_TYPE (type);
if (TREE_CODE (init) == TREE_LIST)
- init = build_x_compound_expr_from_list (init, ELK_INIT,
- tf_warning_or_error);
+ {
+ /* This handles (C++20 only) code like
+
+ const A& r(1, 2, 3);
+
+ where we treat the parenthesized list as a CONSTRUCTOR. */
+ if (TREE_TYPE (init) == NULL_TREE
+ && CP_AGGREGATE_TYPE_P (ttype)
+ && !DECL_DECOMPOSITION_P (decl)
+ && (cxx_dialect >= cxx2a))
+ {
+ init = build_constructor_from_list (init_list_type_node, init);
+ CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+ }
+ else
+ init = build_x_compound_expr_from_list (init, ELK_INIT,
+ tf_warning_or_error);
+ }
- tree ttype = TREE_TYPE (type);
if (TREE_CODE (ttype) != ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
/* Note: default conversion is only called in very special cases. */
@@ -6437,6 +6454,11 @@ reshape_init (tree type, tree init, tsubst_flags_t
complain)
if (vec_safe_is_empty (v))
return init;
+ /* Brace elision is not performed for a CONSTRUCTOR representing
+ parenthesized aggregate initialization. */
+ if (CONSTRUCTOR_IS_PAREN_INIT (init))
+ return init;
+
/* Handle [dcl.init.list] direct-list-initialization from
single element of enumeration with a fixed underlying type. */
if (is_direct_enum_init (type, init))
@@ -6640,6 +6662,41 @@ check_initializer (tree decl, tree init, int flags,
vec<tree, va_gc> **cleanups)
flags |= LOOKUP_NO_NARROWING;
}
}
+ /* [dcl.init] "Otherwise, if the destination type is an array, the object
+ is initialized as follows..." So handle things like
+
+ int a[](1, 2, 3);
+
+ which is permitted in C++20 by P0960. */
+ else if (TREE_CODE (init) == TREE_LIST
+ && TREE_TYPE (init) == NULL_TREE
+ && TREE_CODE (type) == ARRAY_TYPE
+ && !DECL_DECOMPOSITION_P (decl)
+ && (cxx_dialect >= cxx2a))
+ {
+ /* [dcl.init.string] "An array of ordinary character type [...]
+ can be initialized by an ordinary string literal [...] by an
+ appropriately-typed string literal enclosed in braces" only
+ talks about braces, but GCC has always accepted
+
+ char a[]("foobar");
+
+ so we continue to do so. */
+ tree val = TREE_VALUE (init);
+ if (TREE_CHAIN (init) == NULL_TREE
+ && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ && TREE_CODE (tree_strip_any_location_wrapper (val))
+ == STRING_CST)
+ /* If the list has a single element and it's a string literal,
+ then it's the initializer for the array as a whole. */
+ init = val;
+ else
+ {
+ init = build_constructor_from_list (init_list_type_node, init);
+ CONSTRUCTOR_IS_DIRECT_INIT (init) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (init) = true;
+ }
+ }
else if (TREE_CODE (init) == TREE_LIST
&& TREE_TYPE (init) != unknown_type_node
&& !MAYBE_CLASS_TYPE_P (type))
@@ -6683,6 +6740,9 @@ check_initializer (tree decl, tree init, int flags,
vec<tree, va_gc> **cleanups)
init_code = TREE_OPERAND (init_code, 0);
if (TREE_CODE (init_code) == INIT_EXPR)
{
+ /* In C++20, the call to build_aggr_init could have created
+ an INIT_EXPR with a CONSTRUCTOR as the RHS to handle
+ A(1, 2). */
init = TREE_OPERAND (init_code, 1);
init_code = NULL_TREE;
/* Don't call digest_init; it's unnecessary and will complain
@@ -6736,7 +6796,7 @@ check_initializer (tree decl, tree init, int flags,
vec<tree, va_gc> **cleanups)
0, "array %qD initialized by parenthesized "
"string literal %qE",
decl, DECL_INITIAL (decl));
- init = NULL;
+ init = NULL_TREE;
}
}
else
diff --git gcc/cp/tree.c gcc/cp/tree.c
index 8817860b4d3..8b625e8b18e 100644
--- gcc/cp/tree.c
+++ gcc/cp/tree.c
@@ -669,6 +669,15 @@ build_aggr_init_expr (tree type, tree init)
tree
build_cplus_new (tree type, tree init, tsubst_flags_t complain)
{
+ /* This function should cope with what build_special_member_call
+ can produce. When performing parenthesized aggregate initialization,
+ it can produce a { }. */
+ if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ {
+ gcc_assert (cxx_dialect >= cxx2a);
+ return finish_compound_literal (type, init, complain);
+ }
+
tree rval = build_aggr_init_expr (type, init);
tree slot;
diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index ae00de2468d..7fda6266a35 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -1117,6 +1117,10 @@ digest_init_r (tree type, tree init, int nested, int
flags,
tree stripped_init = init;
+ if (BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_IS_PAREN_INIT (init))
+ flags |= LOOKUP_AGGREGATE_PAREN_INIT;
+
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue
(g++.old-deja/g++.law/casts2.C). */
if (TREE_CODE (init) == NON_LVALUE_EXPR)
@@ -1224,7 +1228,9 @@ digest_init_r (tree type, tree init, int nested, int
flags,
if ((code != COMPLEX_TYPE || BRACE_ENCLOSED_INITIALIZER_P (stripped_init))
&& (SCALAR_TYPE_P (type) || code == REFERENCE_TYPE))
{
- if (nested)
+ /* Narrowing is OK when initializing an aggregate from
+ a parenthesized list. */
+ if (nested && !(flags & LOOKUP_AGGREGATE_PAREN_INIT))
flags |= LOOKUP_NO_NARROWING;
init = convert_for_initialization (0, type, init, flags,
ICR_INIT, NULL_TREE, 0,
@@ -1386,9 +1392,12 @@ static tree
massage_init_elt (tree type, tree init, int nested, int flags,
tsubst_flags_t complain)
{
- flags &= LOOKUP_ALLOW_FLEXARRAY_INIT;
- flags |= LOOKUP_IMPLICIT;
- init = digest_init_r (type, init, nested ? 2 : 1, flags, complain);
+ int new_flags = LOOKUP_IMPLICIT;
+ if (flags & LOOKUP_ALLOW_FLEXARRAY_INIT)
+ new_flags |= LOOKUP_ALLOW_FLEXARRAY_INIT;
+ if (flags & LOOKUP_AGGREGATE_PAREN_INIT)
+ new_flags |= LOOKUP_AGGREGATE_PAREN_INIT;
+ init = digest_init_r (type, init, nested ? 2 : 1, new_flags, complain);
/* Strip a simple TARGET_EXPR when we know this is an initializer. */
if (SIMPLE_TARGET_EXPR_P (init))
init = TARGET_EXPR_INITIAL (init);
diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-99.C
gcc/testsuite/g++.dg/cpp0x/constexpr-99.C
index 8d791dd032d..4d3953d0983 100644
--- gcc/testsuite/g++.dg/cpp0x/constexpr-99.C
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-99.C
@@ -9,5 +9,6 @@ struct A
struct B
{
A a;
- constexpr B() : a(0) {} // { dg-error "no matching function" }
+ // P0960R3 allows paren-init.
+ constexpr B() : a(0) {} // { dg-error "no matching function" "" { target
c++17_down } }
};
diff --git gcc/testsuite/g++.dg/cpp0x/explicit7.C
gcc/testsuite/g++.dg/cpp0x/explicit7.C
index 574796d117d..67b50542bc3 100644
--- gcc/testsuite/g++.dg/cpp0x/explicit7.C
+++ gcc/testsuite/g++.dg/cpp0x/explicit7.C
@@ -10,7 +10,7 @@ struct A { };
struct B: A { };
struct C {
explicit operator B*(); // { dg-message "explicit" }
- explicit operator B&(); // { dg-message "explicit" }
+ explicit operator B&(); // { dg-message "explicit" "" { target c++17_down }
}
};
C c;
diff --git gcc/testsuite/g++.dg/cpp0x/initlist12.C
gcc/testsuite/g++.dg/cpp0x/initlist12.C
index f72a6dac525..c2a2b86520f 100644
--- gcc/testsuite/g++.dg/cpp0x/initlist12.C
+++ gcc/testsuite/g++.dg/cpp0x/initlist12.C
@@ -6,15 +6,15 @@ struct A
int i;
};
-A a({1,2}); // { dg-error "no match" }
+A a({1,2}); // { dg-error "no match|cannot convert" }
union U
{
int i,j;
};
-U u({1,2}); // { dg-error "no match" }
+U u({1,2}); // { dg-error "no match|cannot convert" }
union V {};
-V v({1}); // { dg-error "no match" }
+V v({1}); // { dg-error "no match|too many initializers" }
diff --git gcc/testsuite/g++.dg/cpp0x/pr31437.C
gcc/testsuite/g++.dg/cpp0x/pr31437.C
index 7e2ed7a1375..532b533c8d3 100644
--- gcc/testsuite/g++.dg/cpp0x/pr31437.C
+++ gcc/testsuite/g++.dg/cpp0x/pr31437.C
@@ -1,9 +1,9 @@
// { dg-do compile { target c++11 } }
-template <typename... T> struct A // { dg-message "candidates|A" }
+template <typename... T> struct A // { dg-message "candidates|A" "" { target
c++17_down } }
{
A(T* p) { // { dg-error "parameter packs|T" }
(A<T...>*)(p);
}
};
-A<int> a(0); // { dg-error "no matching" }
+A<int> a(0); // { dg-error "no matching|too many initializers" }
diff --git gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index 9b6e2f59d2c..389b25e16ea 100644
--- gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -460,6 +460,12 @@
# error "__cpp_constexpr_dynamic_alloc != 201907"
#endif
+#ifndef __cpp_aggregate_paren_init
+# error "__cpp_aggregate_paren_init"
+#elif __cpp_aggregate_paren_init != 201902
+# error "__cpp_aggregate_paren_init != 201902"
+#endif
+
#ifdef __has_cpp_attribute
# if ! __has_cpp_attribute(maybe_unused)
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init1.C
gcc/testsuite/g++.dg/cpp2a/paren-init1.C
new file mode 100644
index 00000000000..a54b2ccaf6d
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init1.C
@@ -0,0 +1,116 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do run { target c++2a } }
+
+struct A {
+ int i;
+ int j;
+ int k;
+};
+
+struct B {
+ int i;
+ int j;
+ int k = 42;
+};
+
+struct C {
+ A a;
+};
+
+struct D {
+ A a1;
+ A a2;
+};
+
+struct E {
+ int i;
+};
+
+// F has a base class, but it's not virtual, private, or protected, so this is
+// still an aggregate (since C++17).
+struct F : E {
+ int j;
+ int k;
+};
+
+F f({1}, 2, 3);
+
+// A non-virtual member function doesn't make it a non-aggregate.
+struct G {
+ int i;
+ double j;
+ int foo(int, int);
+};
+
+G g(1, 2.14);
+
+class H {
+public:
+ H (int) { }
+};
+
+class I : public H { };
+
+int i;
+A a1(1, 2);
+A a2(1.0, 2);
+A a3(++i, ++i);
+const A& ra(1, 2);
+
+A ca = A(1, 2);
+A ca2 = A(1.0, 2);
+A ca3 = A(++i, ++i);
+const A& rca = A(1, 2);
+
+B b1(1, 2, 3);
+B b2(1, 2);
+B b3(1);
+
+C c1({5, 6, 7});
+D d1({1, 2, 3}, {5, 6, 7});
+
+struct W {
+ const char *s, *t;
+};
+W w1("fluffer", "nutter");
+
+struct Y {
+ char a[4];
+};
+Y y("yew");
+
+int
+main ()
+{
+ I(10);
+
+ // A::k will be value-initialized.
+ if (a1.i != 1 || a1.j != 2 || a1.k != 0)
+ __builtin_abort ();
+ if (a2.i != 1 || a2.j != 2 || a2.k != 0)
+ __builtin_abort ();
+ if (a3.i != 1 || a3.j != 2 || a3.k != 0)
+ __builtin_abort ();
+ if (ra.i != 1 || ra.j != 2 || ra.k != 0)
+ __builtin_abort ();
+ if (ca.i != 1 || ca.j != 2 || ca.k != 0)
+ __builtin_abort ();
+ if (ca2.i != 1 || ca2.j != 2 || ca2.k != 0)
+ __builtin_abort ();
+ if (ca3.i != 3 || ca3.j != 4 || ca3.k != 0)
+ __builtin_abort ();
+
+ if (b1.i != 1 || b1.j != 2 || b1.k != 3)
+ __builtin_abort ();
+ // The default member initializer will be used for B::k.
+ if (b2.i != 1 || b2.j != 2 || b2.k != 42)
+ __builtin_abort ();
+ if (b3.i != 1 || b3.j != 0 || b3.k != 42)
+ __builtin_abort ();
+
+ if (c1.a.i != 5 || c1.a.j != 6 || c1.a.k != 7)
+ __builtin_abort ();
+
+ if (f.i != 1 || f.j != 2 || f.k != 3)
+ __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init10.C
gcc/testsuite/g++.dg/cpp2a/paren-init10.C
new file mode 100644
index 00000000000..5c70d9d59ee
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init10.C
@@ -0,0 +1,18 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+// Test from [dcl.init].
+
+struct A {
+ int a;
+ int&& r;
+};
+
+int f();
+int n = 10;
+
+A a1{1, f()}; // OK, lifetime is extended
+A a2(1, f()); // well-formed, but dangling reference
+A a3{1.0, 1}; // { dg-error "narrowing conversion" }
+A a4(1.0, 1); // well-formed, but dangling reference
+A a5(1.0, static_cast<int&&>(n)); // OK
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init11.C
gcc/testsuite/g++.dg/cpp2a/paren-init11.C
new file mode 100644
index 00000000000..82ca2669545
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init11.C
@@ -0,0 +1,88 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+// Test ill-formed code.
+
+// If k is greater than the size of the array, the program is ill-formed.
+int a1[2](1, 2, 3); // { dg-error "too many initializers" }
+int a2[](); // { dg-error "array of functions" }
+int a3[](()); // { dg-error "expected primary-expression" }
+int a4[]("raccoon"); // { dg-error "invalid conversion" }
+
+struct S {
+ int i;
+ int j;
+};
+
+S s1(1, 1, 1); // { dg-error "too many initializers" }
+
+union U2 {
+ int a;
+ float b;
+};
+
+// [dcl.init.aggr]/19:
+// When a union is initialized with an initializer list, there shall not be
+// more than one explicitly initialized element.
+U2 u4 = U2(1, 2); // { dg-error "too many initializers" }
+
+// Test there is no brace elision.
+
+int a[2][2](1, 2, 3, 4); // { dg-error "too many initializers|array must be
initialized with a brace-enclosed initializer" }
+
+// private/protected/virtual base class -> not an aggregate.
+struct B { };
+struct D : private B {
+ int i;
+ int j;
+};
+
+D d({}, 1, 2); // { dg-error "no matching function" }
+
+// Private non-static data member -> not an aggregate.
+struct P {
+ int i;
+private:
+ int j;
+};
+
+P p(1, 2); // { dg-error "no matching function" }
+
+// User-declared constructor -> not an aggregate.
+struct U {
+ U() {}
+ int i;
+ int j;
+};
+
+U u(1, 2); // { dg-error "no matching function" }
+
+// virtual member function -> not an aggregate.
+struct V {
+ int i;
+ int j;
+ virtual int foo(int);
+};
+
+V v(1, 2); // { dg-error "no matching function" }
+
+struct nonaggr {
+ int i;
+ int j;
+private:
+ int x;
+};
+
+struct F {
+ nonaggr n;
+ F() : n(1) { } // { dg-error "no matching function" }
+};
+
+struct G {
+ char a[4];
+};
+
+struct H {
+ G g;
+ H() : g("oaks") { } // { dg-error "initializer-string" }
+};
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init12.C
gcc/testsuite/g++.dg/cpp2a/paren-init12.C
new file mode 100644
index 00000000000..d7be6f2b55d
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init12.C
@@ -0,0 +1,17 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct A;
+
+struct C {
+ operator A();
+};
+
+struct A {
+ C c;
+};
+
+C c;
+A a(c); // invokes C’s conversion function to A
+
+// { dg-final { scan-assembler "_ZN1Ccv1AEv" } }
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init13.C
gcc/testsuite/g++.dg/cpp2a/paren-init13.C
new file mode 100644
index 00000000000..4b9107c70ff
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init13.C
@@ -0,0 +1,16 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct X { int a, b; };
+struct Y { X x; };
+
+void
+f()
+{
+ // This is ok...
+ Y y1{{1, 2}};
+ Y y2({1, 2});
+ // ...but Y y((1,2)) is not the same as Y y{{1,2}}. (1, 2) is a
+ // COMPOUND_EXPR.
+ Y y3((1, 2)); // { dg-error "could not convert" }
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init14.C
gcc/testsuite/g++.dg/cpp2a/paren-init14.C
new file mode 100644
index 00000000000..837f9531260
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init14.C
@@ -0,0 +1,10 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++11 } }
+
+struct A {
+ int x;
+ int y;
+ A(int, int) = delete;
+};
+
+A a(1, 2); // { dg-error "use of deleted function" }
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init15.C
gcc/testsuite/g++.dg/cpp2a/paren-init15.C
new file mode 100644
index 00000000000..4311dd4df59
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init15.C
@@ -0,0 +1,35 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct A {
+ int i;
+ int j;
+};
+
+struct B : A
+{
+ B (): A(1.7, 2) { }
+};
+
+void f(A);
+
+void
+g ()
+{
+ f (A(1, 2));
+}
+
+struct S {
+ int a[2];
+};
+
+S h() { return S({1, 2}); }
+
+struct Z {
+ int i;
+ int j;
+ operator A();
+};
+
+Z z;
+A a = Z(1, 2.3);
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init16.C
gcc/testsuite/g++.dg/cpp2a/paren-init16.C
new file mode 100644
index 00000000000..c8ed924877e
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init16.C
@@ -0,0 +1,14 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct S { int a[2]; };
+struct A { S s[1]; };
+
+template <typename, int N>
+struct R { static constexpr auto h = A({S{N}}); };
+
+template <typename, int N>
+struct R2 { static constexpr auto h = A({S({N, N})}); };
+
+A foo = R<int, 10>::h;
+A foo2 = R2<int, 10>::h;
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init17.C
gcc/testsuite/g++.dg/cpp2a/paren-init17.C
new file mode 100644
index 00000000000..8e08b5288a5
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init17.C
@@ -0,0 +1,6 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++11 } }
+
+struct A { };
+struct B { };
+static_assert (!__is_trivially_constructible(A, B), "");
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init18.C
gcc/testsuite/g++.dg/cpp2a/paren-init18.C
new file mode 100644
index 00000000000..0aea493f214
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init18.C
@@ -0,0 +1,9 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct A { int a, b, c; };
+struct S { A a; };
+constexpr S s{ A(1, 2, 3) };
+static_assert (s.a.a == 1 && s.a.b == 2 && s.a.c == 3);
+constexpr S s2 = { A(1, 2, 3) };
+static_assert (s2.a.a == 1 && s2.a.b == 2 && s2.a.c == 3);
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init19.C
gcc/testsuite/g++.dg/cpp2a/paren-init19.C
new file mode 100644
index 00000000000..73643fa3aa2
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init19.C
@@ -0,0 +1,12 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct A {
+ int i[2];
+};
+
+A a({1});
+A a2({1, 2});
+A a3(1); // { dg-error "array must be initialized with a brace-enclosed
initializer" }
+A a4 = A(1); // { dg-error "array must be initialized with a brace-enclosed
initializer" }
+A a5 = A({1});
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init2.C
gcc/testsuite/g++.dg/cpp2a/paren-init2.C
new file mode 100644
index 00000000000..e9e90d7acb6
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init2.C
@@ -0,0 +1,56 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do run { target c++2a } }
+
+struct A {
+ int i = 0;
+ int j = 0;
+};
+
+struct B {
+ A a;
+ constexpr B() : a(1.1, 2) { }
+};
+
+struct C {
+ int i;
+};
+
+struct E {
+ C c;
+ E() : c(1.2) { }
+};
+
+struct F {
+ char a[4];
+};
+
+struct G {
+ F f;
+ G() : f("yew") { }
+};
+
+struct H {
+ int i;
+ int &&r;
+};
+
+int f() { return 42; }
+
+struct I {
+ H h;
+ I() : h(1, f()) { }
+};
+
+I i; // dangling ref to f():
+ // {.i=1, .r=(int &) &TARGET_EXPR <D.2118, f ()>}
+
+int
+main ()
+{
+ B b;
+ if (b.a.i != 1 || b.a.j != 2)
+ __builtin_abort ();
+ E e;
+ if (e.c.i != 1)
+ __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init3.C
gcc/testsuite/g++.dg/cpp2a/paren-init3.C
new file mode 100644
index 00000000000..f444005a09f
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init3.C
@@ -0,0 +1,11 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+class a {
+ int b{};
+};
+class c {
+ c();
+ a d;
+};
+c::c() {}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init4.C
gcc/testsuite/g++.dg/cpp2a/paren-init4.C
new file mode 100644
index 00000000000..f8c7bd10b63
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init4.C
@@ -0,0 +1,142 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do run { target c++2a } }
+
+// Test T[]().
+
+int i;
+int a1[](1, 2, 3);
+static_assert(sizeof(a1) == 3 * sizeof (int), "");
+int a2[](1.0, 2, 3);
+static_assert(sizeof(a2) == 3 * sizeof (int), "");
+int a3[3](1, 2, 3);
+int a4[3](1, 2); // a4[2] is value-initialized.
+int a5[](++i, ++i);
+static_assert(sizeof(a5) == 2 * sizeof (int), "");
+int a6[](1);
+static_assert(sizeof(a6) == sizeof (int), "");
+int a7[]({});
+static_assert(sizeof(a7) == sizeof (int), "");
+int a8[]({}, {}, {}, {}, {}, {});
+static_assert(sizeof(a8) == 6 * sizeof (int), "");
+int a9[]((1));
+static_assert(sizeof(a9) == sizeof (int), "");
+int a10[]((1), (2), (3));
+static_assert(sizeof(a10) == 3 * sizeof (int), "");
+int a11[][2]{1};
+static_assert(sizeof(a11) == 2 * sizeof (int), "");
+int a12[][2]({1, 2}, {3, 4});
+static_assert(sizeof(a12) == 4 * sizeof (int), "");
+
+const int (&ra1)[](1, 2);
+const int (&ra2)[](1.0, 2);
+const int (&ra3)[2](1.0, 2);
+int (&&rra1)[](1, 2);
+int (&&rra2)[](1.0, 2);
+int (&&rra3)[2](1.0, 2);
+
+struct S { int i; } s;
+S s1[]({1});
+static_assert(sizeof(s1) == sizeof (S), "");
+S s2[]({1}, {2});
+static_assert(sizeof(s2) == 2 * sizeof (S), "");
+S s3[]({1}, {2}, {3});
+static_assert(sizeof(s3) == 3 * sizeof (S), "");
+S s4[3]({1}, {2});
+static_assert(sizeof(s4) == 3 * sizeof (S), "");
+S s5[]({++i}, {++i});
+static_assert(sizeof(s2) == 2 * sizeof (S), "");
+S s6[](s, s);
+
+struct R { int i; int j; };
+R r1[]({1, 2});
+static_assert(sizeof(r1) == sizeof (R), "");
+R r2[]({1, 2}, {3, 4});
+static_assert(sizeof(r2) == 2 * sizeof (R), "");
+R r3[]({1.0, 2}, {3.2, 4});
+static_assert(sizeof(r3) == 2 * sizeof (R), "");
+
+char c1[]('r');
+char c2[]('r', 'a', 'c', 'c', 'o', 'o', 'n');
+char c3[]("yarrow");
+char c4[4]("oak");
+char c5[10]("cat");
+const char (&c6)[4]("eel");
+
+int g;
+struct X {
+ int i;
+ X() { ++g; }
+ X(int) { };
+};
+
+int
+main ()
+{
+ // Here we'll value-initialize l[1] and l[2], which will zero-initialize it.
+ int l[3](42);
+ if (l[0] != 42 || l[1] != 0 || l[2] != 0)
+ __builtin_abort ();
+
+ // Here we'll value-initialize x[2] and x[3]. Since X is a class type
+ // with a user-provided ctor, we'll default-initialize in both cases.
+ X x[4]({ 1 }, { 2 });
+ if (g != 2)
+ __builtin_abort ();
+
+ if (a1[0] != 1 || a1[1] != 2 || a1[2] != 3)
+ __builtin_abort ();
+ if (a2[0] != 1 || a2[1] != 2 || a2[2] != 3)
+ __builtin_abort ();
+ if (a3[0] != 1 || a3[1] != 2 || a3[2] != 3)
+ __builtin_abort ();
+ if (a4[0] != 1 || a4[1] != 2 || a4[2] != 0)
+ __builtin_abort ();
+ if (a5[0] != 1 || a5[1] != 2)
+ __builtin_abort ();
+ if (a6[0] != 1)
+ __builtin_abort ();
+ if (a7[0] != 0)
+ __builtin_abort ();
+ if (a8[0] != 0 || a8[1] != 0 || a8[2] != 0 || a8[3] != 0
+ || a8[4] != 0 || a8[5] != 0)
+ __builtin_abort ();
+ if (a9[0] != 1)
+ __builtin_abort ();
+ if (a10[0] != 1 || a10[1] != 2 || a10[2] != 3)
+ __builtin_abort ();
+ if (a11[0][0] != 1 || a11[0][1] != 0)
+ __builtin_abort ();
+ if (a12[0][0] != 1 || a12[0][1] != 2 || a12[1][0] != 3 || a12[1][1] != 4)
+ __builtin_abort ();
+
+ if (ra1[0] != 1 || ra1[1] != 2)
+ __builtin_abort ();
+ if (ra2[0] != 1 || ra2[1] != 2)
+ __builtin_abort ();
+ if (ra3[0] != 1 || ra3[1] != 2)
+ __builtin_abort ();
+ if (rra1[0] != 1 || rra1[1] != 2)
+ __builtin_abort ();
+ if (rra2[0] != 1 || rra2[1] != 2)
+ __builtin_abort ();
+ if (rra3[0] != 1 || rra3[1] != 2)
+ __builtin_abort ();
+
+ if (s1[0].i != 1)
+ __builtin_abort ();
+ if (s2[0].i != 1 || s2[1].i != 2)
+ __builtin_abort ();
+ if (s3[0].i != 1 || s3[1].i != 2 || s3[2].i != 3)
+ __builtin_abort ();
+ if (s4[0].i != 1 || s4[1].i != 2 || s4[2].i != 0)
+ __builtin_abort ();
+ if (s5[0].i != 3 || s5[1].i != 4)
+ __builtin_abort ();
+
+ if (r1[0].i != 1 || r1[0].j != 2)
+ __builtin_abort ();
+ if (r2[0].i != 1 || r2[0].j != 2 || r2[1].i != 3 || r2[1].j != 4)
+ __builtin_abort ();
+ if (r3[0].i != 1 || r3[0].j != 2 || r3[1].i != 3 || r3[1].j != 4)
+ __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init5.C
gcc/testsuite/g++.dg/cpp2a/paren-init5.C
new file mode 100644
index 00000000000..a64cb00ebbc
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init5.C
@@ -0,0 +1,25 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do run { target c++2a } }
+
+union U {
+ int a;
+ float b;
+};
+
+// u1 has no active member
+U u1;
+// u2 zero-initializes the first member, so u2.a is the active member and
+// its value is 0.
+U u2 = U();
+// u3 uses non-list aggregate initialization, so u3.a is the active member
+// and its value is 1.
+U u3 = U(1);
+
+int
+main ()
+{
+ if (u2.a != 0)
+ __builtin_abort ();
+ if (u3.a != 1)
+ __builtin_abort ();
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init6.C
gcc/testsuite/g++.dg/cpp2a/paren-init6.C
new file mode 100644
index 00000000000..b5d97dcb3d8
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init6.C
@@ -0,0 +1,14 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+// Test that we don't perform lifetime extension for () init.
+
+struct A {
+ int a;
+ int&& r;
+};
+
+int f();
+A a(1, f());
+
+// { dg-final { scan-assembler-not "_ZGR1a" } }
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init7.C
gcc/testsuite/g++.dg/cpp2a/paren-init7.C
new file mode 100644
index 00000000000..32af1a7265c
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init7.C
@@ -0,0 +1,20 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do run { target c++2a } }
+
+int h;
+struct i {
+ i() {}
+ explicit i(i &) {}
+ template <typename j> i(j &) { h++; }
+};
+
+int main() {
+ {
+ i a[6];
+ auto [b, c, d, e, f, g] = a;
+ }
+ i a[6];
+ auto [b, c, d, e, f, g](a);
+ if (h != 6)
+ __builtin_abort();
+}
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init8.C
gcc/testsuite/g++.dg/cpp2a/paren-init8.C
new file mode 100644
index 00000000000..30e71650bc9
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init8.C
@@ -0,0 +1,13 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+// Test that we don't accept designated inits in ( ).
+
+struct S {
+ int i;
+ int j = 42;
+};
+
+S s(.i = 12); // { dg-error "expected" }
+
+int a[]([0] = 42); // { dg-error "" }
diff --git gcc/testsuite/g++.dg/cpp2a/paren-init9.C
gcc/testsuite/g++.dg/cpp2a/paren-init9.C
new file mode 100644
index 00000000000..c44b206feb8
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp2a/paren-init9.C
@@ -0,0 +1,10 @@
+// PR c++/91363 - P0960R3: Parenthesized initialization of aggregates.
+// { dg-do compile { target c++2a } }
+
+struct B { };
+struct A : B {
+ int i;
+};
+
+B b;
+A a(b);
diff --git gcc/testsuite/g++.dg/ext/desig10.C gcc/testsuite/g++.dg/ext/desig10.C
index 24057dd0ad6..c8d672b72d9 100644
--- gcc/testsuite/g++.dg/ext/desig10.C
+++ gcc/testsuite/g++.dg/ext/desig10.C
@@ -1,4 +1,4 @@
// PR c++/84972
// { dg-additional-options "-w" }
-char(a[])({.a = 0}); // { dg-error "designated initializer" }
+char(a[])({.a = 0}); // { dg-error "designated initializer|cannot convert" }
diff --git gcc/testsuite/g++.dg/template/crash107.C
gcc/testsuite/g++.dg/template/crash107.C
index 3b0b4e8211f..9d8d394d93d 100644
--- gcc/testsuite/g++.dg/template/crash107.C
+++ gcc/testsuite/g++.dg/template/crash107.C
@@ -3,7 +3,7 @@
// { dg-options "" }
// { dg-additional-options "-Wno-return-type" }
-template<typename FP_> struct Vec { // { dg-message "note" }
+template<typename FP_> struct Vec { // { dg-message "note" "" { target
c++17_down } }
Vec& operator^=(Vec& rhs) {
union {
struct {FP_ x,y,z;}; // { dg-error "20:anonymous struct" }
@@ -14,6 +14,6 @@ template<typename FP_> struct Vec { // { dg-message "note" }
return Vec(*this)^=rhs; // { dg-message "required" }
}
};
-Vec<double> v(3,4,12); // { dg-error "no matching" }
-Vec<double> V(12,4,3); // { dg-error "no matching" }
+Vec<double> v(3,4,12); // { dg-error "no matching|too many initializers" }
+Vec<double> V(12,4,3); // { dg-error "no matching|too many initializers" }
Vec<double> c = v^V; // { dg-message "required" }
diff --git gcc/testsuite/g++.dg/template/crash95.C
gcc/testsuite/g++.dg/template/crash95.C
index f60e635ae66..47346111328 100644
--- gcc/testsuite/g++.dg/template/crash95.C
+++ gcc/testsuite/g++.dg/template/crash95.C
@@ -8,4 +8,4 @@ template < typename > struct S
};
};
-S < int > s(0); // { dg-error "no matching" }
+S < int > s(0); // { dg-error "no matching|too many initializers" }
diff --git gcc/testsuite/g++.old-deja/g++.jason/crash3.C
gcc/testsuite/g++.old-deja/g++.jason/crash3.C
index e94cc7c9781..c4950531328 100644
--- gcc/testsuite/g++.old-deja/g++.jason/crash3.C
+++ gcc/testsuite/g++.old-deja/g++.jason/crash3.C
@@ -2,12 +2,13 @@
// Bug: g++ tries to generate initialization semantics for a Node from an int,
// and fails.
-struct Node // { dg-message "note" }
+struct Node // { dg-message "note" "" { target c++17_down }
}
{
Node* child[2];
};
void bug(int i)
{
- Node* q = new Node(i); // { dg-error "no matching" }
+ Node* q = new Node(i); // { dg-error "no matching" "" { target
c++17_down } }
+// { dg-error "array must be initialized" "" { target c++2a } .-1 }
}
diff --git gcc/testsuite/g++.old-deja/g++.law/ctors11.C
gcc/testsuite/g++.old-deja/g++.law/ctors11.C
index 39ee76b0ae7..b29b18a62a3 100644
--- gcc/testsuite/g++.old-deja/g++.law/ctors11.C
+++ gcc/testsuite/g++.old-deja/g++.law/ctors11.C
@@ -10,12 +10,12 @@ public:
inline A(int x){printf("constructing A with %d\n", x);}
};
-class B:public A{ // { dg-message "note" } non-default constructor
+class B:public A{ // { dg-message "note" "" { target c++17_down } }
non-default constructor
private:
public:
};
int main()
{
- B(10);// { dg-error "match" } B doesn't have a constructor taking int
+ B(10);// { dg-error "match" "" { target c++17_down } } B doesn't have a
constructor taking int
}
diff --git gcc/testsuite/g++.old-deja/g++.law/ctors9.C
gcc/testsuite/g++.old-deja/g++.law/ctors9.C
index 43ba1262c95..5856d5dc883 100644
--- gcc/testsuite/g++.old-deja/g++.law/ctors9.C
+++ gcc/testsuite/g++.old-deja/g++.law/ctors9.C
@@ -20,7 +20,7 @@ Foo::Foo(int aa)
{ }
-struct var_Foo: public Foo // { dg-message "note" } base.*// ERROR - in class.*
+struct var_Foo: public Foo // { dg-message "note" "" { target c++17_down } }
base.*// ERROR - in class.*
{
var_Foo* operator-> () {return this;}
};
@@ -32,7 +32,7 @@ int blort(Foo& f)
int main()
{
- var_Foo b(2);// { dg-error "match" }
+ var_Foo b(2);// { dg-error "match" "" { target c++17_down } }
b->a = 0;
int x = blort(b);
return x;
diff --git gcc/testsuite/g++.old-deja/g++.mike/net22.C
gcc/testsuite/g++.old-deja/g++.mike/net22.C
index e5e1cb1081d..abbf6191023 100644
--- gcc/testsuite/g++.old-deja/g++.mike/net22.C
+++ gcc/testsuite/g++.old-deja/g++.mike/net22.C
@@ -5,10 +5,11 @@ public:
Parent( char *s ) {}
};
-class Child : public Parent { // { dg-message "note" } called
+class Child : public Parent { // { dg-message "note" "" { target
c++17_down } } called
};
int main() {
- Child c( "String initializer" ); // { dg-error "match" } bad
+ Child c( "String initializer" ); // { dg-error "match" "" { target
c++17_down } } bad
+// { dg-error "forbids converting a string constant" "" { target c++2a } .-1 }
return 0;
}
diff --git gcc/testsuite/g++.old-deja/g++.niklas/t128.C
gcc/testsuite/g++.old-deja/g++.niklas/t128.C
index 19e3ca1dab0..0b3346c4ef3 100644
--- gcc/testsuite/g++.old-deja/g++.niklas/t128.C
+++ gcc/testsuite/g++.old-deja/g++.niklas/t128.C
@@ -1,5 +1,5 @@
// { dg-do assemble }
// GROUPS niklas uncaught default-construct
struct A { A (int); };
-struct B : A {}; // { dg-message "note" } without ctor // ERROR - candidates
-void f () { B (0); }// { dg-error "match" } .*
+struct B : A {}; // { dg-message "note" "" { target c++17_down } } without
ctor // ERROR - candidates
+void f () { B (0); }// { dg-error "match" "" { target c++17_down } } .*