Someone on IRC complained that there was no way to suppress -Wunused on structured bindings. It seemed to me that the way the feature works, we shouldn't warn about the bindings individually; users need to give each of the subobjects a name even if they're only interested in using one of them.
So this patch switches to tracking whether the underlying aggregate object as a whole is used; using one of the bindings will avoid any warning. This doesn't apply to tuple structured bindings, since in that case the bindings are actual variables rather than aliases to subobjects. Tested x86_64-pc-linux-gnu, applying to trunk.
commit a10b737bee6f269c6d6cf2a668d03fb322e1c45e Author: Jason Merrill <ja...@redhat.com> Date: Thu May 11 13:30:24 2017 -0400 -Wunused and C++17 structured bindings * decl.c (poplevel): Don't warn about unused structured bindings, only real variables. * error.c (dump_simple_decl): Handle structured bindings. * expr.c (mark_exp_read): Look through DECL_VALUE_EXPR. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5877f37..afd47bb 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -656,7 +656,10 @@ poplevel (int keep, int reverse, int functionbody) if (VAR_P (decl) && (! TREE_USED (decl) || !DECL_READ_P (decl)) && ! DECL_IN_SYSTEM_HEADER (decl) - && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl) + /* For structured bindings, consider only real variables, not + subobjects. */ + && (DECL_DECOMPOSITION_P (decl) ? !DECL_VALUE_EXPR (decl) + : (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl))) && type != error_mark_node && (!CLASS_TYPE_P (type) || !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index b65cee4..66a4b60 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -992,6 +992,8 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags) else dump_decl (pp, DECL_NAME (t), flags); } + else if (DECL_DECOMPOSITION_P (t)) + pp_string (pp, M_("<structured bindings>")); else pp_string (pp, M_("<anonymous>")); if (flags & TFF_DECL_SPECIFIERS) diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 77af54e..75e99e5 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -133,6 +133,9 @@ mark_exp_read (tree exp) switch (TREE_CODE (exp)) { case VAR_DECL: + if (DECL_VALUE_EXPR (exp)) + mark_exp_read (DECL_VALUE_EXPR (exp)); + gcc_fallthrough (); case PARM_DECL: DECL_READ_P (exp) = 1; break; diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp29.C b/gcc/testsuite/g++.dg/cpp1z/decomp29.C new file mode 100644 index 0000000..daf07a0 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/decomp29.C @@ -0,0 +1,26 @@ +// { dg-options "-std=c++17 -Wunused" } + +#include <tuple> + +struct A { int i,j,k; }; + +A f(); + +int z; + +int main() +{ + { + auto [i,j,k] = f(); // { dg-warning "unused" } + } + { + auto [i,j,k] = f(); + z = i; + } + { + auto [i,j] = std::tuple{1,2}; // { dg-warning "unused" } + } + // No parallel second test, because in this case i and j are variables rather + // than mere bindings, so there isn't a link between them and using i will + // not prevent a warning about unused j. +}