cp-tree.h (struct lang_decl_decomp): New type.
* cp-tree.h (struct lang_decl_decomp): New type. (struct lang_decl): Add u.decomp. (LANG_DECL_DECOMP_CHECK): Define. (DECL_DECOMPOSITION_P): Note it is set also on the vars for user identifiers. (DECL_DECOMP_BASE): Define. (retrofit_lang_decl): Add extra int = 0 argument. * lex.c (retrofit_lang_decl): Add SEL argument, if non-zero use it to influence the selector choices and for selector 0 to non-zero transition copy old content. (cxx_dup_lang_specific_decl): Handle DECL_DECOMPOSITION_P. * decl.c (poplevel): For DECL_DECOMPOSITION_P, check !DECL_DECOMP_BASE instead of !DECL_VALUE_EXPR. Adjust warning wording if decl is a structured binding. (cp_finish_decomp): Pass 4 as the new argument to retrofit_lang_decl. Set DECL_DECOMP_BASE. Ignore DECL_READ_P sets from initialization of individual variables for tuple structured bindings. (grokdeclarator): Pass 4 as the new argument to retrofit_lang_decl. Clear DECL_DECOMP_BASE. * decl2.c (mark_used): Mark DECL_DECOMP_BASE TREE_USED as well. * pt.c (tsubst_decomp_names): Assert DECL_DECOMP_BASE matches what is expected. * expr.c (mark_exp_read): Recurse on DECL_DECOMP_BASE instead of DECL_VALUE_EXPR. * g++.dg/cpp1z/decomp29.C (p): New variable. (main): Add further tests. From-SVN: r248483
This commit is contained in:
parent
28e0e05bad
commit
6fc9f7aa73
|
@ -1,3 +1,30 @@
|
|||
2017-05-26 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* cp-tree.h (struct lang_decl_decomp): New type.
|
||||
(struct lang_decl): Add u.decomp.
|
||||
(LANG_DECL_DECOMP_CHECK): Define.
|
||||
(DECL_DECOMPOSITION_P): Note it is set also on the vars
|
||||
for user identifiers.
|
||||
(DECL_DECOMP_BASE): Define.
|
||||
(retrofit_lang_decl): Add extra int = 0 argument.
|
||||
* lex.c (retrofit_lang_decl): Add SEL argument, if non-zero
|
||||
use it to influence the selector choices and for selector
|
||||
0 to non-zero transition copy old content.
|
||||
(cxx_dup_lang_specific_decl): Handle DECL_DECOMPOSITION_P.
|
||||
* decl.c (poplevel): For DECL_DECOMPOSITION_P, check
|
||||
!DECL_DECOMP_BASE instead of !DECL_VALUE_EXPR. Adjust warning
|
||||
wording if decl is a structured binding.
|
||||
(cp_finish_decomp): Pass 4 as the new argument to retrofit_lang_decl.
|
||||
Set DECL_DECOMP_BASE. Ignore DECL_READ_P sets from initialization
|
||||
of individual variables for tuple structured bindings.
|
||||
(grokdeclarator): Pass 4 as the new argument to retrofit_lang_decl.
|
||||
Clear DECL_DECOMP_BASE.
|
||||
* decl2.c (mark_used): Mark DECL_DECOMP_BASE TREE_USED as well.
|
||||
* pt.c (tsubst_decomp_names): Assert DECL_DECOMP_BASE matches what
|
||||
is expected.
|
||||
* expr.c (mark_exp_read): Recurse on DECL_DECOMP_BASE instead of
|
||||
DECL_VALUE_EXPR.
|
||||
|
||||
2017-05-25 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/80605 - __is_standard_layout and zero-length array
|
||||
|
|
|
@ -2516,6 +2516,15 @@ struct GTY(()) lang_decl_parm {
|
|||
int index;
|
||||
};
|
||||
|
||||
/* Additional DECL_LANG_SPECIFIC information for structured bindings. */
|
||||
|
||||
struct GTY(()) lang_decl_decomp {
|
||||
struct lang_decl_min min;
|
||||
/* The artificial underlying "e" variable of the structured binding
|
||||
variable. */
|
||||
tree base;
|
||||
};
|
||||
|
||||
/* DECL_LANG_SPECIFIC for all types. It would be nice to just make this a
|
||||
union rather than a struct containing a union as its only field, but
|
||||
tree.h declares it as a struct. */
|
||||
|
@ -2527,6 +2536,7 @@ struct GTY(()) lang_decl {
|
|||
struct lang_decl_fn GTY ((tag ("1"))) fn;
|
||||
struct lang_decl_ns GTY((tag ("2"))) ns;
|
||||
struct lang_decl_parm GTY((tag ("3"))) parm;
|
||||
struct lang_decl_decomp GTY((tag ("4"))) decomp;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -2563,6 +2573,13 @@ struct GTY(()) lang_decl {
|
|||
lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \
|
||||
<->u.parm; })
|
||||
|
||||
#define LANG_DECL_DECOMP_CHECK(NODE) __extension__ \
|
||||
({ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \
|
||||
if (!VAR_P (NODE) \
|
||||
|| lt->u.base.selector != 4) \
|
||||
lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \
|
||||
<->u.decomp; })
|
||||
|
||||
#define LANG_DECL_U2_CHECK(NODE, TF) __extension__ \
|
||||
({ struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE); \
|
||||
if (!LANG_DECL_HAS_MIN (NODE) || lt->u.base.u2sel != TF) \
|
||||
|
@ -2583,6 +2600,9 @@ struct GTY(()) lang_decl {
|
|||
#define LANG_DECL_PARM_CHECK(NODE) \
|
||||
(&DECL_LANG_SPECIFIC (NODE)->u.parm)
|
||||
|
||||
#define LANG_DECL_DECOMP_CHECK(NODE) \
|
||||
(&DECL_LANG_SPECIFIC (NODE)->u.decomp)
|
||||
|
||||
#define LANG_DECL_U2_CHECK(NODE, TF) \
|
||||
(&DECL_LANG_SPECIFIC (NODE)->u.min.u2)
|
||||
|
||||
|
@ -3816,8 +3836,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
|||
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \
|
||||
= true)
|
||||
|
||||
/* Nonzero if NODE is an artificial VAR_DECL for a C++17 decomposition
|
||||
declaration. */
|
||||
/* Nonzero if NODE is an artificial VAR_DECL for a C++17 structured binding
|
||||
declaration or one of VAR_DECLs for the user identifiers in it. */
|
||||
#define DECL_DECOMPOSITION_P(NODE) \
|
||||
(VAR_P (NODE) && DECL_LANG_SPECIFIC (NODE) \
|
||||
? DECL_LANG_SPECIFIC (NODE)->u.base.decomposition_p \
|
||||
|
@ -3826,6 +3846,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|
|||
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.decomposition_p \
|
||||
= true)
|
||||
|
||||
/* The underlying artificial VAR_DECL for structured binding. */
|
||||
#define DECL_DECOMP_BASE(NODE) \
|
||||
(LANG_DECL_DECOMP_CHECK (NODE)->base)
|
||||
|
||||
/* Nonzero if NODE is an inline VAR_DECL. In C++17, static data members
|
||||
declared with constexpr specifier are implicitly inline variables. */
|
||||
#define DECL_INLINE_VAR_P(NODE) \
|
||||
|
@ -6261,7 +6285,7 @@ extern tree unqualified_name_lookup_error (tree,
|
|||
extern tree unqualified_fn_lookup_error (cp_expr);
|
||||
extern tree build_lang_decl (enum tree_code, tree, tree);
|
||||
extern tree build_lang_decl_loc (location_t, enum tree_code, tree, tree);
|
||||
extern void retrofit_lang_decl (tree);
|
||||
extern void retrofit_lang_decl (tree, int = 0);
|
||||
extern tree copy_decl (tree CXX_MEM_STAT_INFO);
|
||||
extern tree copy_type (tree CXX_MEM_STAT_INFO);
|
||||
extern tree cxx_make_type (enum tree_code);
|
||||
|
|
|
@ -658,7 +658,7 @@ poplevel (int keep, int reverse, int functionbody)
|
|||
&& ! DECL_IN_SYSTEM_HEADER (decl)
|
||||
/* For structured bindings, consider only real variables, not
|
||||
subobjects. */
|
||||
&& (DECL_DECOMPOSITION_P (decl) ? !DECL_VALUE_EXPR (decl)
|
||||
&& (DECL_DECOMPOSITION_P (decl) ? !DECL_DECOMP_BASE (decl)
|
||||
: (DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)))
|
||||
&& type != error_mark_node
|
||||
&& (!CLASS_TYPE_P (type)
|
||||
|
@ -667,16 +667,28 @@ poplevel (int keep, int reverse, int functionbody)
|
|||
TYPE_ATTRIBUTES (TREE_TYPE (decl)))))
|
||||
{
|
||||
if (! TREE_USED (decl))
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_variable, "unused variable %qD", decl);
|
||||
{
|
||||
if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl))
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_variable,
|
||||
"unused structured binding declaration");
|
||||
else
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_variable, "unused variable %qD", decl);
|
||||
}
|
||||
else if (DECL_CONTEXT (decl) == current_function_decl
|
||||
// For -Wunused-but-set-variable leave references alone.
|
||||
&& TREE_CODE (TREE_TYPE (decl)) != REFERENCE_TYPE
|
||||
&& errorcount == unused_but_set_errorcount)
|
||||
{
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_but_set_variable,
|
||||
"variable %qD set but not used", decl);
|
||||
if (!DECL_NAME (decl) && DECL_DECOMPOSITION_P (decl))
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_but_set_variable, "structured "
|
||||
"binding declaration set but not used");
|
||||
else
|
||||
warning_at (DECL_SOURCE_LOCATION (decl),
|
||||
OPT_Wunused_but_set_variable,
|
||||
"variable %qD set but not used", decl);
|
||||
unused_but_set_errorcount = errorcount;
|
||||
}
|
||||
}
|
||||
|
@ -7361,8 +7373,9 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
|
|||
}
|
||||
if (processing_template_decl)
|
||||
{
|
||||
retrofit_lang_decl (first);
|
||||
retrofit_lang_decl (first, 4);
|
||||
SET_DECL_DECOMPOSITION_P (first);
|
||||
DECL_DECOMP_BASE (first) = decl;
|
||||
}
|
||||
first = DECL_CHAIN (first);
|
||||
}
|
||||
|
@ -7375,8 +7388,9 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
|
|||
for (unsigned int i = 0; i < count; i++, d = DECL_CHAIN (d))
|
||||
{
|
||||
v[count - i - 1] = d;
|
||||
retrofit_lang_decl (d);
|
||||
retrofit_lang_decl (d, 4);
|
||||
SET_DECL_DECOMPOSITION_P (d);
|
||||
DECL_DECOMP_BASE (d) = decl;
|
||||
}
|
||||
|
||||
tree type = TREE_TYPE (decl);
|
||||
|
@ -7482,6 +7496,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
|
|||
eltscnt = tree_to_uhwi (tsize);
|
||||
if (count != eltscnt)
|
||||
goto cnt_mismatch;
|
||||
int save_read = DECL_READ_P (decl);
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
location_t sloc = input_location;
|
||||
|
@ -7514,6 +7529,10 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
|
|||
cp_finish_decl (v[i], init, /*constexpr*/false,
|
||||
/*asm*/NULL_TREE, LOOKUP_NORMAL);
|
||||
}
|
||||
/* Ignore reads from the underlying decl performed during initialization
|
||||
of the individual variables. If those will be read, we'll mark
|
||||
the underlying decl as read at that point. */
|
||||
DECL_READ_P (decl) = save_read;
|
||||
}
|
||||
else if (TREE_CODE (type) == UNION_TYPE)
|
||||
{
|
||||
|
@ -12295,9 +12314,10 @@ grokdeclarator (const cp_declarator *declarator,
|
|||
{
|
||||
gcc_assert (declarator && declarator->kind == cdk_decomp);
|
||||
DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
|
||||
retrofit_lang_decl (decl);
|
||||
retrofit_lang_decl (decl, 4);
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
SET_DECL_DECOMPOSITION_P (decl);
|
||||
DECL_DECOMP_BASE (decl) = NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5027,6 +5027,9 @@ mark_used (tree decl, tsubst_flags_t complain)
|
|||
|
||||
/* Set TREE_USED for the benefit of -Wunused. */
|
||||
TREE_USED (decl) = 1;
|
||||
/* And for structured bindings also the underlying decl. */
|
||||
if (DECL_DECOMPOSITION_P (decl) && DECL_DECOMP_BASE (decl))
|
||||
TREE_USED (DECL_DECOMP_BASE (decl)) = 1;
|
||||
|
||||
if (TREE_CODE (decl) == TEMPLATE_DECL)
|
||||
return true;
|
||||
|
|
|
@ -133,8 +133,8 @@ mark_exp_read (tree exp)
|
|||
switch (TREE_CODE (exp))
|
||||
{
|
||||
case VAR_DECL:
|
||||
if (DECL_VALUE_EXPR (exp))
|
||||
mark_exp_read (DECL_VALUE_EXPR (exp));
|
||||
if (DECL_DECOMPOSITION_P (exp))
|
||||
mark_exp_read (DECL_DECOMP_BASE (exp));
|
||||
gcc_fallthrough ();
|
||||
case PARM_DECL:
|
||||
DECL_READ_P (exp) = 1;
|
||||
|
|
24
gcc/cp/lex.c
24
gcc/cp/lex.c
|
@ -529,16 +529,28 @@ build_lang_decl_loc (location_t loc, enum tree_code code, tree name, tree type)
|
|||
and pushdecl (for functions generated by the back end). */
|
||||
|
||||
void
|
||||
retrofit_lang_decl (tree t)
|
||||
retrofit_lang_decl (tree t, int sel)
|
||||
{
|
||||
struct lang_decl *ld;
|
||||
size_t size;
|
||||
int sel;
|
||||
size_t oldsize = 0;
|
||||
|
||||
if (DECL_LANG_SPECIFIC (t))
|
||||
return;
|
||||
{
|
||||
if (sel)
|
||||
{
|
||||
if (DECL_LANG_SPECIFIC (t)->u.base.selector == sel)
|
||||
return;
|
||||
gcc_assert (DECL_LANG_SPECIFIC (t)->u.base.selector == 0);
|
||||
oldsize = sizeof (struct lang_decl_min);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (TREE_CODE (t) == FUNCTION_DECL)
|
||||
if (sel == 4)
|
||||
size = sizeof (struct lang_decl_decomp);
|
||||
else if (TREE_CODE (t) == FUNCTION_DECL)
|
||||
sel = 1, size = sizeof (struct lang_decl_fn);
|
||||
else if (TREE_CODE (t) == NAMESPACE_DECL)
|
||||
sel = 2, size = sizeof (struct lang_decl_ns);
|
||||
|
@ -550,6 +562,8 @@ retrofit_lang_decl (tree t)
|
|||
gcc_unreachable ();
|
||||
|
||||
ld = (struct lang_decl *) ggc_internal_cleared_alloc (size);
|
||||
if (oldsize)
|
||||
memcpy (ld, DECL_LANG_SPECIFIC (t), oldsize);
|
||||
|
||||
ld->u.base.selector = sel;
|
||||
|
||||
|
@ -584,6 +598,8 @@ cxx_dup_lang_specific_decl (tree node)
|
|||
size = sizeof (struct lang_decl_ns);
|
||||
else if (TREE_CODE (node) == PARM_DECL)
|
||||
size = sizeof (struct lang_decl_parm);
|
||||
else if (DECL_DECOMPOSITION_P (node))
|
||||
size = sizeof (struct lang_decl_decomp);
|
||||
else if (LANG_DECL_HAS_MIN (node))
|
||||
size = sizeof (struct lang_decl_min);
|
||||
else
|
||||
|
|
|
@ -15705,6 +15705,7 @@ tsubst_decomp_names (tree decl, tree pattern_decl, tree args,
|
|||
return error_mark_node;
|
||||
}
|
||||
(*cnt)++;
|
||||
gcc_assert (DECL_DECOMP_BASE (decl2) == pattern_decl);
|
||||
gcc_assert (DECL_HAS_VALUE_EXPR_P (decl2));
|
||||
tree v = DECL_VALUE_EXPR (decl2);
|
||||
DECL_HAS_VALUE_EXPR_P (decl2) = 0;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2017-05-26 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* g++.dg/cpp1z/decomp29.C (p): New variable.
|
||||
(main): Add further tests.
|
||||
|
||||
2017-05-26 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/80842
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
struct A { int i,j,k; };
|
||||
|
||||
A f();
|
||||
int p[3];
|
||||
|
||||
int z;
|
||||
|
||||
|
@ -13,14 +14,43 @@ int main()
|
|||
{
|
||||
auto [i,j,k] = f(); // { dg-warning "unused" }
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] auto [i,j,k] = f();
|
||||
}
|
||||
{
|
||||
auto [i,j,k] = f();
|
||||
z = i;
|
||||
}
|
||||
{
|
||||
auto [i,j,k] = f(); // { dg-warning "unused" }
|
||||
i = 5;
|
||||
}
|
||||
{
|
||||
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.
|
||||
{
|
||||
[[maybe_unused]] auto [i,j] = std::tuple{1,2};
|
||||
}
|
||||
{
|
||||
auto [i,j] = std::tuple{1,2};
|
||||
z = i;
|
||||
}
|
||||
{
|
||||
auto [i,j] = std::tuple{1,2};
|
||||
i = 5;
|
||||
}
|
||||
{
|
||||
auto [i,j,k] = p; // { dg-warning "unused" }
|
||||
}
|
||||
{
|
||||
[[maybe_unused]] auto [i,j,k] = p;
|
||||
}
|
||||
{
|
||||
auto [i,j,k] = p;
|
||||
z = i;
|
||||
}
|
||||
{
|
||||
auto [i,j,k] = p; // { dg-warning "unused" }
|
||||
i = 5;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue