diff options
author | Jakub Jelinek <jakub@redhat.com> | 2021-10-29 09:28:32 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2021-10-29 09:28:32 +0200 |
commit | eca767aa51d1f69614222ceb130ca6bb07713232 (patch) | |
tree | 6fd22f2e45dab8a8542eeeff6ace686b4dd9e035 /gcc | |
parent | 146b83e14a0a76a9ce8a4cb79997a078f437f779 (diff) | |
download | gcc-eca767aa51d1f69614222ceb130ca6bb07713232.zip gcc-eca767aa51d1f69614222ceb130ca6bb07713232.tar.gz gcc-eca767aa51d1f69614222ceb130ca6bb07713232.tar.bz2 |
c++: Implement DR2351 - void{} [PR102820]
Here is an implementation of DR2351 - void{} - where void{} after
pack expansion is considered valid and the same thing as void().
For templates, if CONSTRUCTOR_NELTS is 0, the CONSTRUCTOR is not dependent
and we can return void_node right away, if it is dependent and contains
only packs, then it is potentially zero element and so we need to build
CONSTRUCTOR_IS_DEPENDENT CONSTRUCTOR, while if it contains any non-pack
elts, we can diagnose it right away.
2021-10-29 Jakub Jelinek <jakub@redhat.com>
PR c++/102820
* semantics.c (maybe_zero_constructor_nelts): New function.
(finish_compound_literal): Implement DR2351 - void{}.
If type is cv void and compound_literal has no elements, return
void_node. If type is cv void and compound_literal might have no
elements after expansion, handle it like other dependent compound
literals.
* g++.dg/cpp0x/dr2351.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/semantics.c | 33 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/dr2351.C | 51 |
2 files changed, 81 insertions, 3 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 3072ecd..2443d03 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3079,6 +3079,22 @@ finish_unary_op_expr (location_t op_loc, enum tree_code code, cp_expr expr, return result; } +/* Return true if CONSTRUCTOR EXPR after pack expansion could have no + elements. */ + +static bool +maybe_zero_constructor_nelts (tree expr) +{ + if (CONSTRUCTOR_NELTS (expr) == 0) + return true; + if (!processing_template_decl) + return false; + for (constructor_elt &elt : CONSTRUCTOR_ELTS (expr)) + if (!PACK_EXPANSION_P (elt.value)) + return false; + return true; +} + /* Finish a compound-literal expression or C++11 functional cast with aggregate initializer. TYPE is the type to which the CONSTRUCTOR in COMPOUND_LITERAL is being cast. */ @@ -3104,9 +3120,20 @@ finish_compound_literal (tree type, tree compound_literal, if (!TYPE_OBJ_P (type)) { - if (complain & tf_error) - error ("compound literal of non-object type %qT", type); - return error_mark_node; + /* DR2351 */ + if (VOID_TYPE_P (type) && CONSTRUCTOR_NELTS (compound_literal) == 0) + return void_node; + else if (VOID_TYPE_P (type) + && processing_template_decl + && maybe_zero_constructor_nelts (compound_literal)) + /* If there are only packs in compound_literal, it could + be void{} after pack expansion. */; + else + { + if (complain & tf_error) + error ("compound literal of non-object type %qT", type); + return error_mark_node; + } } if (template_placeholder_p (type)) diff --git a/gcc/testsuite/g++.dg/cpp0x/dr2351.C b/gcc/testsuite/g++.dg/cpp0x/dr2351.C new file mode 100644 index 0000000..5116dfe --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/dr2351.C @@ -0,0 +1,51 @@ +// DR2351 +// { dg-do compile { target c++11 } } + +void +foo () +{ + void{}; + void(); +} + +template <class ...T> +void +bar (T... t) +{ + void{t...}; + void(t...); +} + +void +baz () +{ + bar (); +} + +template <class ...T> +void +qux (T... t) +{ + void{t...}; // { dg-error "compound literal of non-object type" } +} + +void +corge () +{ + qux (1, 2); +} + +template <class ...T> +void +garply (T... t) +{ + void{t..., t..., t...}; + void(t..., t..., t...); +} + +template <class ...T> +void +grault (T... t) +{ + void{t..., 1}; // { dg-error "compound literal of non-object type" } +} |