@@ -1537,7 +1537,7 @@ extern void maybe_warn_unused_local_typedefs (void);
extern void maybe_warn_bool_compare (location_t, enum tree_code, tree, tree);
extern bool maybe_warn_shift_overflow (location_t, tree, tree);
extern void warn_duplicated_cond_add_or_warn (location_t, tree, vec<tree> **);
-extern bool diagnose_mismatched_attributes (tree, tree);
+extern bool diagnose_mismatched_attributes (tree, tree, tree, tree);
extern tree do_warn_duplicated_branches_r (tree *, int *, void *);
extern void warn_for_multistatement_macros (location_t, location_t,
location_t, enum rid);
@@ -2125,7 +2125,8 @@ warn_duplicated_cond_add_or_warn (location_t loc, tree cond, vec<tree> **chain)
attributes, such as always_inline vs. noinline. */
bool
-diagnose_mismatched_attributes (tree olddecl, tree newdecl)
+diagnose_mismatched_attributes (tree olddecl, tree newdecl, tree oldtype,
+ tree newtype)
{
bool warned = false;
@@ -2172,6 +2173,17 @@ diagnose_mismatched_attributes (tree olddecl, tree newdecl)
warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
"%qs follows declaration with attribute %qs",
newdecl, "hot", "cold");
+ else if (lookup_attribute ("noreturn", DECL_ATTRIBUTES (newdecl))
+ && lookup_attribute ("warn_unused_result",
+ TYPE_ATTRIBUTES (oldtype)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "noreturn", "warn_unused_result");
+ else if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (newtype))
+ && lookup_attribute ("noreturn", DECL_ATTRIBUTES (olddecl)))
+ warned |= warning (OPT_Wattributes, "declaration of %q+D with attribute "
+ "%qs follows declaration with attribute %qs",
+ newdecl, "warn_unused_result", "noreturn");
return warned;
}
@@ -2234,7 +2234,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
- warned |= diagnose_mismatched_attributes (olddecl, newdecl);
+ warned |= diagnose_mismatched_attributes (olddecl, newdecl, oldtype,
+ newtype);
else /* PARM_DECL, VAR_DECL */
{
/* Redeclaration of a parameter is a constraint violation (this is
@@ -1397,7 +1397,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
if (DECL_P (olddecl)
&& TREE_CODE (newdecl) == FUNCTION_DECL
&& TREE_CODE (olddecl) == FUNCTION_DECL
- && diagnose_mismatched_attributes (olddecl, newdecl))
+ && diagnose_mismatched_attributes (olddecl, newdecl,
+ TREE_TYPE (olddecl),
+ TREE_TYPE (newdecl)))
{
if (DECL_INITIAL (olddecl))
inform (DECL_SOURCE_LOCATION (olddecl),
@@ -0,0 +1,8 @@
+/* PR c/81544 */
+/* { dg-do compile } */
+
+int __attribute__ ((noreturn)) foo (void); /* { dg-message "previous declaration" } */
+int __attribute__ ((warn_unused_result)) foo (void); /* { dg-warning "attribute .warn_unused_result. follows declaration with attribute .noreturn." } */
+
+int __attribute__ ((warn_unused_result)) foo2 (void); /* { dg-message "previous declaration" } */
+int __attribute__ ((noreturn)) foo2 (void); /* { dg-warning "attribute .noreturn. follows declaration with attribute .warn_unused_result." } */