c++: source position of lambda captures [PR84471]

If the DECL_VALUE_EXPR of a VAR_DECL has EXPR_LOCATION set, then any use of
that variable looks like it has that location, which leads to the debugger
jumping back and forth for both lambdas and structured bindings.

Rather than fix all the uses, it seems simplest to remove any EXPR_LOCATION
when setting DECL_VALUE_EXPR.  So the cp/ hunks aren't necessary, but they
avoid the need to unshare to remove the location.

	PR c++/84471
	PR c++/107504

gcc/cp/ChangeLog:

	* coroutines.cc (transform_local_var_uses): Don't
	specify a location for DECL_VALUE_EXPR.
	* decl.cc (cp_finish_decomp): Likewise.

gcc/ChangeLog:

	* fold-const.cc (protected_set_expr_location_unshare): Not static.
	* tree.h: Declare it.
	* tree.cc (decl_value_expr_insert): Use it.

include/ChangeLog:

	* ansidecl.h (ATTRIBUTE_WARN_UNUSED_RESULT): Add __.

gcc/testsuite/ChangeLog:

	* g++.dg/tree-ssa/value-expr1.C: New test.
	* g++.dg/tree-ssa/value-expr2.C: New test.
	* g++.dg/analyzer/pr93212.C: Move warning.
This commit is contained in:
Jason Merrill 2022-12-01 22:58:28 -05:00
parent a996888327
commit 302485a70a
9 changed files with 56 additions and 15 deletions

View file

@ -2047,8 +2047,8 @@ transform_local_var_uses (tree *stmt, int *do_subtree, void *d)
= lookup_member (lvd->coro_frame_type, local_var.field_id,
/*protect=*/1, /*want_type=*/0,
tf_warning_or_error);
tree fld_idx = build3_loc (lvd->loc, COMPONENT_REF, TREE_TYPE (lvar),
lvd->actor_frame, fld_ref, NULL_TREE);
tree fld_idx = build3 (COMPONENT_REF, TREE_TYPE (lvar),
lvd->actor_frame, fld_ref, NULL_TREE);
local_var.field_idx = fld_idx;
SET_DECL_VALUE_EXPR (lvar, fld_idx);
DECL_HAS_VALUE_EXPR_P (lvar) = true;

View file

@ -9137,9 +9137,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
if (processing_template_decl)
continue;
tree t = unshare_expr (dexp);
t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
eltype, t, size_int (i), NULL_TREE,
NULL_TREE);
t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
@ -9158,9 +9156,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
if (processing_template_decl)
continue;
tree t = unshare_expr (dexp);
t = build1_loc (DECL_SOURCE_LOCATION (v[i]),
i ? IMAGPART_EXPR : REALPART_EXPR, eltype,
t);
t = build1 (i ? IMAGPART_EXPR : REALPART_EXPR, eltype, t);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}
@ -9184,9 +9180,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
tree t = unshare_expr (dexp);
convert_vector_to_array_for_subscript (DECL_SOURCE_LOCATION (v[i]),
&t, size_int (i));
t = build4_loc (DECL_SOURCE_LOCATION (v[i]), ARRAY_REF,
eltype, t, size_int (i), NULL_TREE,
NULL_TREE);
t = build4 (ARRAY_REF, eltype, t, size_int (i), NULL_TREE, NULL_TREE);
SET_DECL_VALUE_EXPR (v[i], t);
DECL_HAS_VALUE_EXPR_P (v[i]) = 1;
}

View file

@ -164,7 +164,7 @@ expr_location_or (tree t, location_t loc)
/* Similar to protected_set_expr_location, but never modify x in place,
if location can and needs to be set, unshare it. */
static inline tree
tree
protected_set_expr_location_unshare (tree x, location_t loc)
{
if (CAN_HAVE_LOCATION_P (x)

View file

@ -4,8 +4,8 @@
auto lol()
{
int aha = 3;
return [&aha] { // { dg-warning "dereferencing pointer '.*' to within stale stack frame" }
return aha;
return [&aha] {
return aha; // { dg-warning "dereferencing pointer '.*' to within stale stack frame" }
};
/* TODO: may be worth special-casing the reporting of dangling
references from lambdas, to highlight the declaration, and maybe fix

View file

@ -0,0 +1,16 @@
// PR c++/84471
// { dg-do compile { target c++11 } }
// { dg-additional-options -fdump-tree-gimple-lineno }
// { dg-final { scan-tree-dump-not {value-expr: \[} "gimple" } }
int main(int argc, char**)
{
int x = 1;
auto f = [&x, &argc](const char* i) {
i += x;
i -= argc;
i += argc - x;
return i;
};
f(" ");
}

View file

@ -0,0 +1,26 @@
// PR c++/107504
// { dg-do compile { target c++17 } }
// { dg-additional-options -fdump-tree-gimple-lineno }
// { dg-final { scan-tree-dump-not {value-expr: \[} "gimple" } }
struct S
{
void* i;
int j;
};
S f(char* p)
{
return {p, 1};
}
int main()
{
char buf[1];
auto [x, y] = f(buf);
if (x != buf)
throw 1;
if (y != 1)
throw 2;
return 0;
}

View file

@ -5862,6 +5862,9 @@ decl_value_expr_insert (tree from, tree to)
{
struct tree_decl_map *h;
/* Uses of FROM shouldn't look like they happen at the location of TO. */
to = protected_set_expr_location_unshare (to, UNKNOWN_LOCATION);
h = ggc_alloc<tree_decl_map> ();
h->base.from = from;
h->to = to;

View file

@ -1289,6 +1289,8 @@ get_expr_source_range (tree expr)
extern void protected_set_expr_location (tree, location_t);
extern void protected_set_expr_location_if_unset (tree, location_t);
ATTRIBUTE_WARN_UNUSED_RESULT
extern tree protected_set_expr_location_unshare (tree, location_t);
WARN_UNUSED_RESULT extern tree maybe_wrap_with_location (tree, location_t);

View file

@ -279,7 +279,7 @@ So instead we use the macro below and test it against specific values. */
/* Attribute `warn_unused_result' was valid as of gcc 3.3. */
#ifndef ATTRIBUTE_WARN_UNUSED_RESULT
# if GCC_VERSION >= 3003
# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
# define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
# define ATTRIBUTE_WARN_UNUSED_RESULT
# endif