c++: avoid duplicate deprecated warning [PR90451]
We were getting the deprecated warning twice for the same call because we called mark_used first in finish_qualified_id_expr and then again in build_over_call. Let's not call it the first time; C++17 clarified that a function is used only when it is selected from an overload set, which happens later. Then I had to add a few more uses in places that don't do anything further with the expression (convert_to_void, finish_decltype_type), and places that use the expression more unusually (cp_build_addr_expr_1, convert_nontype_argument). The new mark_single_function is mostly so that I only have to put the comment in one place. PR c++/90451 gcc/cp/ChangeLog: * decl2.cc (mark_single_function): New. * cp-tree.h: Declare it. * typeck.cc (cp_build_addr_expr_1): mark_used when making a PMF. * semantics.cc (finish_qualified_id_expr): Not here. (finish_id_expression_1): Or here. (finish_decltype_type): Call mark_single_function. * cvt.cc (convert_to_void): And here. * pt.cc (convert_nontype_argument): And here. * init.cc (build_offset_ref): Adjust assert. gcc/testsuite/ChangeLog: * g++.dg/warn/deprecated-14.C: New test. * g++.dg/warn/deprecated-15.C: New test.
This commit is contained in:
parent
efbb17db52
commit
c352ef0ed9
@ -6930,6 +6930,7 @@ extern void no_linkage_error (tree);
|
||||
extern void check_default_args (tree);
|
||||
extern bool mark_used (tree);
|
||||
extern bool mark_used (tree, tsubst_flags_t);
|
||||
extern bool mark_single_function (tree, tsubst_flags_t);
|
||||
extern void finish_static_data_member_decl (tree, tree, bool, tree, int);
|
||||
extern tree cp_build_parm_decl (tree, tree, tree);
|
||||
extern void copy_linkage (tree, tree);
|
||||
|
@ -1482,6 +1482,9 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
|
||||
default:;
|
||||
}
|
||||
expr = resolve_nondeduced_context (expr, complain);
|
||||
if (!mark_single_function (expr, complain))
|
||||
return error_mark_node;
|
||||
|
||||
{
|
||||
tree probe = expr;
|
||||
|
||||
|
@ -5718,6 +5718,29 @@ decl_dependent_p (tree decl)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* [basic.def.odr] A function is named [and therefore odr-used] by an
|
||||
expression or conversion if it is the selected member of an overload set in
|
||||
an overload resolution performed as part of forming that expression or
|
||||
conversion, unless it is a pure virtual function and either the expression
|
||||
is not an id-expression naming the function with an explicitly qualified
|
||||
name or the expression forms a pointer to member.
|
||||
|
||||
Mostly, we call mark_used in places that actually do something with a
|
||||
function, like build_over_call. But in a few places we end up with a
|
||||
non-overloaded FUNCTION_DECL that we aren't going to do any more with, like
|
||||
convert_to_void. resolve_nondeduced_context is called in those places,
|
||||
but it's also called in too many other places. */
|
||||
|
||||
bool
|
||||
mark_single_function (tree expr, tsubst_flags_t complain)
|
||||
{
|
||||
if (is_overloaded_fn (expr) == 1
|
||||
&& !mark_used (expr, complain)
|
||||
&& (complain & tf_error))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Mark DECL (either a _DECL or a BASELINK) as "used" in the program.
|
||||
If DECL is a specialization or implicitly declared class member,
|
||||
generate the actual definition. Return false if something goes
|
||||
|
@ -2362,8 +2362,9 @@ build_offset_ref (tree type, tree member, bool address_p,
|
||||
return error_mark_node;
|
||||
|
||||
gcc_assert (DECL_P (member) || BASELINK_P (member));
|
||||
/* Callers should call mark_used before this point. */
|
||||
gcc_assert (!DECL_P (member) || TREE_USED (member));
|
||||
/* Callers should call mark_used before this point, except for functions. */
|
||||
gcc_assert (!DECL_P (member) || TREE_USED (member)
|
||||
|| TREE_CODE (member) == FUNCTION_DECL);
|
||||
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
if (!COMPLETE_OR_OPEN_TYPE_P (complete_type (type)))
|
||||
|
@ -7382,6 +7382,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
|
||||
for examples. */
|
||||
if (TYPE_REF_OBJ_P (type) || TYPE_REFFN_P (type))
|
||||
{
|
||||
/* Check this before we strip *& to avoid redundancy. */
|
||||
if (!mark_single_function (expr, complain))
|
||||
return error_mark_node;
|
||||
|
||||
tree probe_type, probe = expr;
|
||||
if (REFERENCE_REF_P (probe))
|
||||
probe = TREE_OPERAND (probe, 0);
|
||||
|
@ -2319,7 +2319,10 @@ finish_qualified_id_expr (tree qualifying_class,
|
||||
if (error_operand_p (expr))
|
||||
return error_mark_node;
|
||||
|
||||
if ((DECL_P (expr) || BASELINK_P (expr))
|
||||
if (DECL_P (expr)
|
||||
/* Functions are marked after overload resolution; avoid redundant
|
||||
warnings. */
|
||||
&& TREE_CODE (expr) != FUNCTION_DECL
|
||||
&& !mark_used (expr, complain))
|
||||
return error_mark_node;
|
||||
|
||||
@ -4198,9 +4201,6 @@ finish_id_expression_1 (tree id_expression,
|
||||
decl = (adjust_result_of_qualified_name_lookup
|
||||
(decl, scope, current_nonlambda_class_type()));
|
||||
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
mark_used (decl);
|
||||
|
||||
cp_warn_deprecated_use_scopes (scope);
|
||||
|
||||
if (TYPE_P (scope))
|
||||
@ -4232,18 +4232,6 @@ finish_id_expression_1 (tree id_expression,
|
||||
tree first_fn = get_first_fn (decl);
|
||||
first_fn = STRIP_TEMPLATE (first_fn);
|
||||
|
||||
/* [basic.def.odr]: "A function whose name appears as a
|
||||
potentially-evaluated expression is odr-used if it is the unique
|
||||
lookup result".
|
||||
|
||||
But only mark it if it's a complete postfix-expression; in a call,
|
||||
ADL might select a different function, and we'll call mark_used in
|
||||
build_over_call. */
|
||||
if (done
|
||||
&& !really_overloaded_fn (decl)
|
||||
&& !mark_used (first_fn))
|
||||
return error_mark_node;
|
||||
|
||||
if (!template_arg_p
|
||||
&& (TREE_CODE (first_fn) == USING_DECL
|
||||
|| (TREE_CODE (first_fn) == FUNCTION_DECL
|
||||
@ -11252,6 +11240,8 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
|
||||
/* The type denoted by decltype(e) is defined as follows: */
|
||||
|
||||
expr = resolve_nondeduced_context (expr, complain);
|
||||
if (!mark_single_function (expr, complain))
|
||||
return error_mark_node;
|
||||
|
||||
if (invalid_nonstatic_memfn_p (input_location, expr, complain))
|
||||
return error_mark_node;
|
||||
|
@ -6854,6 +6854,12 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* Forming a pointer-to-member is a use of non-pure-virtual fns. */
|
||||
if (TREE_CODE (t) == FUNCTION_DECL
|
||||
&& !DECL_PURE_VIRTUAL_P (t)
|
||||
&& !mark_used (t, complain) && !(complain & tf_error))
|
||||
return error_mark_node;
|
||||
|
||||
type = build_ptrmem_type (context_for_name_lookup (t),
|
||||
TREE_TYPE (t));
|
||||
t = make_ptrmem_cst (type, t);
|
||||
|
72
gcc/testsuite/g++.dg/warn/deprecated-14.C
Normal file
72
gcc/testsuite/g++.dg/warn/deprecated-14.C
Normal file
@ -0,0 +1,72 @@
|
||||
// PR c++/90451
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct myclass{
|
||||
[[deprecated("deprecated-static1")]] static void stat1() { }
|
||||
[[deprecated("deprecated-static2")]] static void stat2() { }
|
||||
[[deprecated("deprecated-static3")]] static void stat3() { }
|
||||
[[deprecated("deprecated-static4")]] static void stat4() { }
|
||||
|
||||
[[deprecated("deprecated-non1")]] void non1() { }
|
||||
[[deprecated("deprecated-non2")]] void non2() { }
|
||||
};
|
||||
|
||||
[[deprecated("deprecated-global1")]] void fn1();
|
||||
[[deprecated("deprecated-global2")]] void fn2();
|
||||
[[deprecated("deprecated-global3")]] void fn3();
|
||||
|
||||
[[deprecated("deprecated-global4")]] void fn4();
|
||||
[[deprecated("deprecated-global5")]] void fn5();
|
||||
[[deprecated("deprecated-global6")]] void fn6();
|
||||
[[deprecated("deprecated-global7")]] void fn7();
|
||||
[[deprecated("deprecated-global8")]] void fn8();
|
||||
|
||||
namespace N
|
||||
{
|
||||
[[deprecated("deprecated-ns1")]] void fn1();
|
||||
[[deprecated("deprecated-ns2")]] void fn2();
|
||||
[[deprecated("deprecated-ns3")]] void fn3();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
myclass::stat1(); // { dg-bogus "deprecated-static1.*deprecated-static1" }
|
||||
// { dg-warning "deprecated-static1" "" { target *-*-* } .-1 }
|
||||
&myclass::stat2; // { dg-bogus "deprecated-static2.*deprecated-static2" }
|
||||
// { dg-warning "deprecated-static2" "" { target *-*-* } .-1 }
|
||||
auto x = myclass::stat3; // { dg-bogus "deprecated-static3.*deprecated-static3" }
|
||||
// { dg-warning "deprecated-static3" "" { target *-*-* } .-1 }
|
||||
(void) myclass::stat4; // { dg-bogus "deprecated-static4.*deprecated-static4" }
|
||||
// { dg-warning "deprecated-static4" "" { target *-*-* } .-1 }
|
||||
|
||||
myclass m;
|
||||
m.myclass::non1(); // { dg-bogus "deprecated-non1.*deprecated-non1" }
|
||||
// { dg-warning "deprecated-non1" "" { target *-*-* } .-1 }
|
||||
&myclass::non2; // { dg-bogus "deprecated-non2.*deprecated-non2" }
|
||||
// { dg-warning "deprecated-non2" "" { target *-*-* } .-1 }
|
||||
|
||||
fn1(); // { dg-bogus "deprecated-global1.*deprecated-global1" }
|
||||
// { dg-warning "deprecated-global1" "" { target *-*-* } .-1 }
|
||||
&fn2; // { dg-bogus "deprecated-global2.*deprecated-global2" }
|
||||
// { dg-warning "deprecated-global2" "" { target *-*-* } .-1 }
|
||||
auto xg = fn3; // { dg-bogus "deprecated-global2.*deprecated-global3" }
|
||||
// { dg-warning "deprecated-global3" "" { target *-*-* } .-1 }
|
||||
(void) fn7; // { dg-bogus "deprecated-global7.*deprecated-global7" }
|
||||
// { dg-warning "deprecated-global7" "" { target *-*-* } .-1 }
|
||||
|
||||
::fn4(); // { dg-bogus "deprecated-global4.*deprecated-global4" }
|
||||
// { dg-warning "deprecated-global4" "" { target *-*-* } .-1 }
|
||||
&::fn5; // { dg-bogus "deprecated-global5.*deprecated-global5" }
|
||||
// { dg-warning "deprecated-global5" "" { target *-*-* } .-1 }
|
||||
auto xgs = ::fn6; // { dg-bogus "deprecated-global2.*deprecated-global6" }
|
||||
// { dg-warning "deprecated-global6" "" { target *-*-* } .-1 }
|
||||
(void) ::fn8; // { dg-bogus "deprecated-global8.*deprecated-global8" }
|
||||
// { dg-warning "deprecated-global8" "" { target *-*-* } .-1 }
|
||||
|
||||
N::fn1(); // { dg-bogus "deprecated-ns1.*deprecated-ns1" }
|
||||
// { dg-warning "deprecated-ns1" "" { target *-*-* } .-1 }
|
||||
&N::fn2; // { dg-bogus "deprecated-ns2.*deprecated-ns2" }
|
||||
// { dg-warning "deprecated-ns2" "" { target *-*-* } .-1 }
|
||||
auto xgn = N::fn3; // { dg-bogus "deprecated-ns2.*deprecated-ns3" }
|
||||
// { dg-warning "deprecated-ns3" "" { target *-*-* } .-1 }
|
||||
}
|
14
gcc/testsuite/g++.dg/warn/deprecated-15.C
Normal file
14
gcc/testsuite/g++.dg/warn/deprecated-15.C
Normal file
@ -0,0 +1,14 @@
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
using vfn_t = void();
|
||||
|
||||
template <vfn_t *T> struct A { };
|
||||
template <vfn_t& T> struct B { };
|
||||
|
||||
[[deprecated("deprecated-global1")]] void fn1();
|
||||
[[deprecated("deprecated-global2")]] void fn2();
|
||||
|
||||
A<fn1> a; // { dg-bogus "deprecated-global1.*deprecated-global1" }
|
||||
// { dg-warning "deprecated-global1" "" { target *-*-* } .-1 }
|
||||
B<fn2> b; // { dg-bogus "deprecated-global2.*deprecated-global2" }
|
||||
// { dg-warning "deprecated-global2" "" { target *-*-* } .-1 }
|
Loading…
Reference in New Issue
Block a user