diff options
author | Marek Polacek <polacek@redhat.com> | 2020-04-09 16:31:59 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-04-10 13:54:12 -0400 |
commit | 62c25d7adb1a5664982449dda0e7f9ca63cf4735 (patch) | |
tree | 1886e04120a6fcb60d364bedc5960ee16d1bc451 /gcc/cp/method.c | |
parent | e26bd694c790b7c8f68c6736b2683c60a8fcbcfe (diff) | |
download | gcc-62c25d7adb1a5664982449dda0e7f9ca63cf4735.zip gcc-62c25d7adb1a5664982449dda0e7f9ca63cf4735.tar.gz gcc-62c25d7adb1a5664982449dda0e7f9ca63cf4735.tar.bz2 |
c++: make __is_constructible work with paren-init of aggrs [PR94149]
In C++20 this is well-formed:
using T = int[2];
T t(1, 2);
which means that std::is_constructible_v<int[2], int, int> should be true.
But constructible_expr immediately returned the error_mark_node when it
saw a list with more than one element. To give accurate results in
C++20, we have to try initializing the aggregate from a parenthesized list of
values.
To not repeat the same mistake as in c++/93790, if there's only one
element, I'm trying {} only when () didn't succeed. is_constructible5.C
verifies this.
In paren-init24.C std::is_nothrow_constructible_v doesn't work due to
error: invalid 'static_cast' from type 'int' to type 'int [1]'
and
error: functional cast to array type 'int [2]'
This needs to be fixed in libstdc++.
PR c++/94149
* method.c (constructible_expr): In C++20, try using parenthesized
initialization of aggregates to determine the result of
__is_constructible.
* g++.dg/cpp2a/paren-init24.C: New test.
* g++.dg/cpp2a/paren-init25.C: New test.
* g++.dg/ext/is_constructible5.C: New test.
Diffstat (limited to 'gcc/cp/method.c')
-rw-r--r-- | gcc/cp/method.c | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 9a21bfc..2fb0de2 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1799,12 +1799,48 @@ constructible_expr (tree to, tree from) { if (from == NULL_TREE) return build_value_init (strip_array_types (to), tf_none); - else if (TREE_CHAIN (from)) - return error_mark_node; // too many initializers - from = build_stub_object (TREE_VALUE (from)); + const int len = list_length (from); + if (len > 1) + { + if (cxx_dialect < cxx2a) + /* Too many initializers. */ + return error_mark_node; + + /* In C++20 this is well-formed: + using T = int[2]; + T t(1, 2); + which means that std::is_constructible_v<int[2], int, int> + should be true. */ + vec<constructor_elt, va_gc> *v; + vec_alloc (v, len); + for (tree t = from; t; t = TREE_CHAIN (t)) + { + tree stub = build_stub_object (TREE_VALUE (t)); + constructor_elt elt = { NULL_TREE, stub }; + v->quick_push (elt); + } + from = build_constructor (init_list_type_node, v); + CONSTRUCTOR_IS_DIRECT_INIT (from) = true; + CONSTRUCTOR_IS_PAREN_INIT (from) = true; + } + else + from = build_stub_object (TREE_VALUE (from)); expr = perform_direct_initialization_if_possible (to, from, /*cast*/false, tf_none); + /* If t(e) didn't work, maybe t{e} will. */ + if (expr == NULL_TREE + && len == 1 + && cxx_dialect >= cxx2a) + { + from = build_constructor_single (init_list_type_node, NULL_TREE, + from); + CONSTRUCTOR_IS_DIRECT_INIT (from) = true; + CONSTRUCTOR_IS_PAREN_INIT (from) = true; + expr = perform_direct_initialization_if_possible (to, from, + /*cast*/false, + tf_none); + } } return expr; } |