From 43aae289866f5ea55d187444520412554aa2e171 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 3 Dec 2019 15:59:40 +0000 Subject: [PATCH] PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. This patch implements C++20 P0960R3: Parenthesized initialization of aggregates (; see R0 for more background info). Essentially, if you have an aggregate, you can now initialize it by (x, y), similarly to {x, y}. E.g. struct A { int x, y; // no A(int, int) ctor (see paren-init14.C for = delete; case) }; A a(1, 2); The difference between ()-init and {}-init is that narrowing conversions are permitted, designators are not permitted, a temporary object bound to a reference does not have its lifetime extended, and there is no brace elision. Further, things like int a[](1, 2, 3); // will deduce the array size const A& r(1, 2.3, 3); // narrowing is OK int (&&rr)[](1, 2, 3); int b[3](1, 2); // b[2] will be value-initialized now work as expected. Note that char f[]("fluff"); has always worked and this patch keeps it that way. Also note that A a((1, 2)) is not the same as A a{{1,2}}; the inner (1, 2) remains a COMPOUND_EXPR. The approach I took was to handle (1, 2) similarly to {1, 2} -- conjure up a CONSTRUCTOR, and introduce LOOKUP_AGGREGATE_PAREN_INIT to distinguish between the two. This kind of initialization is only supported in C++20; I've made no attempt to support it in earlier standards, like we don't support CTAD pre-C++17, for instance. * 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. From-SVN: r278939 --- gcc/c-family/ChangeLog | 6 + gcc/c-family/c-cppbuiltin.c | 1 + gcc/cp/ChangeLog | 20 +++ gcc/cp/call.c | 51 ++++++- gcc/cp/cp-tree.h | 7 + gcc/cp/decl.c | 68 ++++++++- gcc/cp/tree.c | 9 ++ gcc/cp/typeck2.c | 17 ++- gcc/testsuite/ChangeLog | 37 +++++ gcc/testsuite/g++.dg/cpp0x/constexpr-99.C | 3 +- gcc/testsuite/g++.dg/cpp0x/explicit7.C | 2 +- gcc/testsuite/g++.dg/cpp0x/initlist12.C | 6 +- gcc/testsuite/g++.dg/cpp0x/pr31437.C | 4 +- gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C | 6 + gcc/testsuite/g++.dg/cpp2a/paren-init1.C | 116 ++++++++++++++ gcc/testsuite/g++.dg/cpp2a/paren-init10.C | 18 +++ gcc/testsuite/g++.dg/cpp2a/paren-init11.C | 88 +++++++++++ gcc/testsuite/g++.dg/cpp2a/paren-init12.C | 17 +++ gcc/testsuite/g++.dg/cpp2a/paren-init13.C | 16 ++ gcc/testsuite/g++.dg/cpp2a/paren-init14.C | 10 ++ gcc/testsuite/g++.dg/cpp2a/paren-init15.C | 35 +++++ gcc/testsuite/g++.dg/cpp2a/paren-init16.C | 14 ++ gcc/testsuite/g++.dg/cpp2a/paren-init17.C | 6 + gcc/testsuite/g++.dg/cpp2a/paren-init18.C | 9 ++ gcc/testsuite/g++.dg/cpp2a/paren-init19.C | 12 ++ gcc/testsuite/g++.dg/cpp2a/paren-init2.C | 56 +++++++ gcc/testsuite/g++.dg/cpp2a/paren-init3.C | 11 ++ gcc/testsuite/g++.dg/cpp2a/paren-init4.C | 142 ++++++++++++++++++ gcc/testsuite/g++.dg/cpp2a/paren-init5.C | 25 +++ gcc/testsuite/g++.dg/cpp2a/paren-init6.C | 14 ++ gcc/testsuite/g++.dg/cpp2a/paren-init7.C | 20 +++ gcc/testsuite/g++.dg/cpp2a/paren-init8.C | 13 ++ gcc/testsuite/g++.dg/cpp2a/paren-init9.C | 10 ++ gcc/testsuite/g++.dg/ext/desig10.C | 2 +- gcc/testsuite/g++.dg/template/crash107.C | 6 +- gcc/testsuite/g++.dg/template/crash95.C | 2 +- gcc/testsuite/g++.old-deja/g++.jason/crash3.C | 5 +- gcc/testsuite/g++.old-deja/g++.law/ctors11.C | 4 +- gcc/testsuite/g++.old-deja/g++.law/ctors9.C | 4 +- gcc/testsuite/g++.old-deja/g++.mike/net22.C | 5 +- gcc/testsuite/g++.old-deja/g++.niklas/t128.C | 4 +- 41 files changed, 868 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init10.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init11.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init12.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init13.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init14.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init15.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init16.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init17.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init18.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init19.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init6.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init7.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init8.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init9.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index fa3b94232fb..f85da5093d8 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2019-12-03 Marek Polacek + + PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. + * c-cppbuiltin.c (c_cpp_builtins): Predefine + __cpp_aggregate_paren_init=201902 for -std=c++2a. + 2019-11-30 Jan Hubicka * c-attribs.c (handle_symver_attribute): New function diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 6491545bc3b..c7f4659456a 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/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 a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7582e1f33a2..c29da7bed79 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,23 @@ +2019-12-03 Marek Polacek + + PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. + * 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. + 2019-12-03 Jakub Jelinek PR c++/92732 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 062cff4c735..ea0e8b7e7d7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -10124,6 +10124,38 @@ build_new_method_call_1 (tree instance, tree fns, vec **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 **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 a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7e810b8ee7b..4af18b0ae62 100644 --- a/gcc/cp/cp-tree.h +++ b/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 a/gcc/cp/decl.c b/gcc/cp/decl.c index 81d73433547..54f09507516 100644 --- a/gcc/cp/decl.c +++ b/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 **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 **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 **cleanups) 0, "array %qD initialized by parenthesized " "string literal %qE", decl, DECL_INITIAL (decl)); - init = NULL; + init = NULL_TREE; } } else diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8817860b4d3..8b625e8b18e 100644 --- a/gcc/cp/tree.c +++ b/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 a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index ae00de2468d..7fda6266a35 100644 --- a/gcc/cp/typeck2.c +++ b/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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 158e09073b1..cc8ff79cbc2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,40 @@ +2019-12-03 Marek Polacek + + PR c++/91363 - P0960R3: Parenthesized initialization of aggregates. + * 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. + 2019-12-03 Richard Biener PR tree-optimization/92645 diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-99.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-99.C index 8d791dd032d..4d3953d0983 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-99.C +++ b/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 a/gcc/testsuite/g++.dg/cpp0x/explicit7.C b/gcc/testsuite/g++.dg/cpp0x/explicit7.C index 574796d117d..67b50542bc3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/explicit7.C +++ b/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 a/gcc/testsuite/g++.dg/cpp0x/initlist12.C b/gcc/testsuite/g++.dg/cpp0x/initlist12.C index f72a6dac525..c2a2b86520f 100644 --- a/gcc/testsuite/g++.dg/cpp0x/initlist12.C +++ b/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 a/gcc/testsuite/g++.dg/cpp0x/pr31437.C b/gcc/testsuite/g++.dg/cpp0x/pr31437.C index 7e2ed7a1375..532b533c8d3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr31437.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr31437.C @@ -1,9 +1,9 @@ // { dg-do compile { target c++11 } } -template struct A // { dg-message "candidates|A" } +template struct A // { dg-message "candidates|A" "" { target c++17_down } } { A(T* p) { // { dg-error "parameter packs|T" } (A*)(p); } }; -A a(0); // { dg-error "no matching" } +A a(0); // { dg-error "no matching|too many initializers" } diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C index 9b6e2f59d2c..389b25e16ea 100644 --- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init1.C b/gcc/testsuite/g++.dg/cpp2a/paren-init1.C new file mode 100644 index 00000000000..a54b2ccaf6d --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init10.C b/gcc/testsuite/g++.dg/cpp2a/paren-init10.C new file mode 100644 index 00000000000..5c70d9d59ee --- /dev/null +++ b/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(n)); // OK diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init11.C b/gcc/testsuite/g++.dg/cpp2a/paren-init11.C new file mode 100644 index 00000000000..82ca2669545 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init12.C b/gcc/testsuite/g++.dg/cpp2a/paren-init12.C new file mode 100644 index 00000000000..d7be6f2b55d --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init13.C b/gcc/testsuite/g++.dg/cpp2a/paren-init13.C new file mode 100644 index 00000000000..4b9107c70ff --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init14.C b/gcc/testsuite/g++.dg/cpp2a/paren-init14.C new file mode 100644 index 00000000000..837f9531260 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init15.C b/gcc/testsuite/g++.dg/cpp2a/paren-init15.C new file mode 100644 index 00000000000..4311dd4df59 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init16.C b/gcc/testsuite/g++.dg/cpp2a/paren-init16.C new file mode 100644 index 00000000000..c8ed924877e --- /dev/null +++ b/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 +struct R { static constexpr auto h = A({S{N}}); }; + +template +struct R2 { static constexpr auto h = A({S({N, N})}); }; + +A foo = R::h; +A foo2 = R2::h; diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init17.C b/gcc/testsuite/g++.dg/cpp2a/paren-init17.C new file mode 100644 index 00000000000..8e08b5288a5 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init18.C b/gcc/testsuite/g++.dg/cpp2a/paren-init18.C new file mode 100644 index 00000000000..0aea493f214 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init19.C b/gcc/testsuite/g++.dg/cpp2a/paren-init19.C new file mode 100644 index 00000000000..73643fa3aa2 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init2.C b/gcc/testsuite/g++.dg/cpp2a/paren-init2.C new file mode 100644 index 00000000000..e9e90d7acb6 --- /dev/null +++ b/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 } + +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 a/gcc/testsuite/g++.dg/cpp2a/paren-init3.C b/gcc/testsuite/g++.dg/cpp2a/paren-init3.C new file mode 100644 index 00000000000..f444005a09f --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init4.C b/gcc/testsuite/g++.dg/cpp2a/paren-init4.C new file mode 100644 index 00000000000..f8c7bd10b63 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init5.C b/gcc/testsuite/g++.dg/cpp2a/paren-init5.C new file mode 100644 index 00000000000..a64cb00ebbc --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init6.C b/gcc/testsuite/g++.dg/cpp2a/paren-init6.C new file mode 100644 index 00000000000..b5d97dcb3d8 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init7.C b/gcc/testsuite/g++.dg/cpp2a/paren-init7.C new file mode 100644 index 00000000000..32af1a7265c --- /dev/null +++ b/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 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 a/gcc/testsuite/g++.dg/cpp2a/paren-init8.C b/gcc/testsuite/g++.dg/cpp2a/paren-init8.C new file mode 100644 index 00000000000..30e71650bc9 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/cpp2a/paren-init9.C b/gcc/testsuite/g++.dg/cpp2a/paren-init9.C new file mode 100644 index 00000000000..c44b206feb8 --- /dev/null +++ b/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 a/gcc/testsuite/g++.dg/ext/desig10.C b/gcc/testsuite/g++.dg/ext/desig10.C index 24057dd0ad6..c8d672b72d9 100644 --- a/gcc/testsuite/g++.dg/ext/desig10.C +++ b/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 a/gcc/testsuite/g++.dg/template/crash107.C b/gcc/testsuite/g++.dg/template/crash107.C index 3b0b4e8211f..9d8d394d93d 100644 --- a/gcc/testsuite/g++.dg/template/crash107.C +++ b/gcc/testsuite/g++.dg/template/crash107.C @@ -3,7 +3,7 @@ // { dg-options "" } // { dg-additional-options "-Wno-return-type" } -template struct Vec { // { dg-message "note" } +template 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 struct Vec { // { dg-message "note" } return Vec(*this)^=rhs; // { dg-message "required" } } }; -Vec v(3,4,12); // { dg-error "no matching" } -Vec V(12,4,3); // { dg-error "no matching" } +Vec v(3,4,12); // { dg-error "no matching|too many initializers" } +Vec V(12,4,3); // { dg-error "no matching|too many initializers" } Vec c = v^V; // { dg-message "required" } diff --git a/gcc/testsuite/g++.dg/template/crash95.C b/gcc/testsuite/g++.dg/template/crash95.C index f60e635ae66..47346111328 100644 --- a/gcc/testsuite/g++.dg/template/crash95.C +++ b/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 a/gcc/testsuite/g++.old-deja/g++.jason/crash3.C b/gcc/testsuite/g++.old-deja/g++.jason/crash3.C index e94cc7c9781..c4950531328 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/crash3.C +++ b/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 a/gcc/testsuite/g++.old-deja/g++.law/ctors11.C b/gcc/testsuite/g++.old-deja/g++.law/ctors11.C index 39ee76b0ae7..b29b18a62a3 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/ctors11.C +++ b/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 a/gcc/testsuite/g++.old-deja/g++.law/ctors9.C b/gcc/testsuite/g++.old-deja/g++.law/ctors9.C index 43ba1262c95..5856d5dc883 100644 --- a/gcc/testsuite/g++.old-deja/g++.law/ctors9.C +++ b/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 a/gcc/testsuite/g++.old-deja/g++.mike/net22.C b/gcc/testsuite/g++.old-deja/g++.mike/net22.C index e5e1cb1081d..abbf6191023 100644 --- a/gcc/testsuite/g++.old-deja/g++.mike/net22.C +++ b/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 a/gcc/testsuite/g++.old-deja/g++.niklas/t128.C b/gcc/testsuite/g++.old-deja/g++.niklas/t128.C index 19e3ca1dab0..0b3346c4ef3 100644 --- a/gcc/testsuite/g++.old-deja/g++.niklas/t128.C +++ b/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 } } .* -- 2.43.5