@@ -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;
@@ -4202,9 +4205,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))
@@ -4236,18 +4236,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
@@ -11256,6 +11244,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);
new file mode 100644
@@ -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 }
+}
new file mode 100644
@@ -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 }