diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 007b928c54b..ef857a9ae2c 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -409,7 +409,7 @@ const struct attribute_spec c_common_attribute_table[] =
      to prevent its usage in source code.  */
   { "no vops",                0, 0, true,  false, false, false,
 			      handle_novops_attribute, NULL },
-  { "deprecated",             0, 1, false, false, false, false,
+  { "deprecated",             0, 2, false, false, false, false,
 			      handle_deprecated_attribute, NULL },
   { "unavailable",            0, 1, false, false, false, false,
 			      handle_unavailable_attribute, NULL },
@@ -4107,6 +4107,21 @@ handle_deprecated_attribute (tree *node, tree name,
       error ("deprecated message is not a string");
       *no_add_attrs = true;
     }
+  else if (TREE_CHAIN (args) != NULL_TREE)
+    {
+      /* We allow an optional second argument in the GNU form of
+	 attribute deprecated, which specifies the replacement.  */
+      if (flags & ATTR_FLAG_CXX11)
+	{
+	  error ("replacement argument only allowed in GNU attributes");
+	  *no_add_attrs = true;
+	}
+      else if (TREE_CODE (TREE_VALUE (TREE_CHAIN (args))) != STRING_CST)
+	{
+	  error ("replacement argument is not a string");
+	  *no_add_attrs = true;
+	}
+    }
 
   if (DECL_P (*node))
     {
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index fa29d2c15fc..2b47f01d166 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4952,6 +4952,14 @@ c_parser_std_attribute (c_parser *parser, bool for_tm)
 	TREE_VALUE (attribute)
 	  = c_parser_attribute_arguments (parser, takes_identifier,
 					  require_string, false);
+	if (c_parser_next_token_is (parser, CPP_COMMA)
+	    && strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0)
+	  {
+	    error_at (open_loc, "replacement argument only allowed in "
+		      "GNU attributes");
+	    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	    return error_mark_node;
+	  }
       }
     else
       c_parser_balanced_token_sequence (parser);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9501a60f20e..7d399f4b2bc 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2860,6 +2860,7 @@ StrongAlias (allocate, alloc);
 
 @item deprecated
 @itemx deprecated (@var{msg})
+@itemx deprecated (@var{msg}, @var{replacement})
 @cindex @code{deprecated} function attribute
 The @code{deprecated} attribute results in a warning if the function
 is used anywhere in the source file.  This is useful when identifying
@@ -2880,6 +2881,13 @@ results in a warning on line 3 but not line 2.  The optional @var{msg}
 argument, which must be a string, is printed in the warning if
 present.
 
+This attribute accepts an optional second argument which specifies
+the replacement that ought to be used instead:
+
+@smallexample
+int old_fn () __attribute__ ((deprecated("unsafe", "new_fn")));
+@end smallexample
+
 The @code{deprecated} attribute can also be used for variables and
 types (@pxref{Variable Attributes}, @pxref{Type Attributes}.)
 
@@ -7409,6 +7417,7 @@ attribute is also not copied.  @xref{Common Function Attributes}.
 
 @item deprecated
 @itemx deprecated (@var{msg})
+@itemx deprecated (@var{msg}, @var{replacement})
 @cindex @code{deprecated} variable attribute
 The @code{deprecated} attribute results in a warning if the variable
 is used anywhere in the source file.  This is useful when identifying
@@ -7429,6 +7438,13 @@ results in a warning on line 3 but not line 2.  The optional @var{msg}
 argument, which must be a string, is printed in the warning if
 present.
 
+This attribute accepts an optional second argument which specifies
+the replacement that ought to be used instead:
+
+@smallexample
+extern int old_var __attribute__ ((deprecated("unsafe", "new_var")));
+@end smallexample
+
 The @code{deprecated} attribute can also be used for functions and
 types (@pxref{Common Function Attributes},
 @pxref{Common Type Attributes}).
@@ -8492,6 +8508,7 @@ struct __attribute__ ((copy ( (struct A *)0)) B @{ /* @r{@dots{}} */ @};
 
 @item deprecated
 @itemx deprecated (@var{msg})
+@itemx deprecated (@var{msg}, @var{replacement})
 @cindex @code{deprecated} type attribute
 The @code{deprecated} attribute results in a warning if the type
 is used anywhere in the source file.  This is useful when identifying
@@ -8522,6 +8539,13 @@ present.  Control characters in the string will be replaced with
 escape sequences, and if the @option{-fmessage-length} option is set
 to 0 (its default value) then any newline characters will be ignored.
 
+This attribute accepts an optional second argument which specifies
+the replacement that ought to be used instead:
+
+@smallexample
+typedef int oldtype __attribute__ ((deprecated("unsafe", "newtype")));
+@end smallexample
+
 The @code{deprecated} attribute can also be used for functions and
 variables (@pxref{Function Attributes}, @pxref{Variable Attributes}.)
 
diff --git a/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c b/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c
new file mode 100644
index 00000000000..b03e0e42ad6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wdeprecated-arg-1.c
@@ -0,0 +1,21 @@
+/* PR c++/102049 */
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+
+typedef int __attribute__((deprecated("obsolete", "newtype"))) oldtype;
+__attribute__((deprecated("unsafe", "get_it_s"))) void get_it (int); /* { dg-message "declared here" } */
+[[gnu::deprecated("g", "")]] void g(); /* { dg-error "only allowed in GNU attributes" } */
+[[deprecated("h", "")]] void h(); /* { dg-error "only allowed in GNU attributes" } */
+__attribute__((deprecated("unsafe", 1))) void f2(); /* { dg-error "argument is not a string" } */
+__attribute__((deprecated("unsafe", "newvar"))) int oldvar; /* { dg-message "declared here" } */
+
+int
+main ()
+{
+  get_it (42); /* { dg-warning "is deprecated: unsafe" } */
+  /* { dg-message "use .get_it_s. instead" "" { target *-*-* } .-1 } */
+  oldtype t; /* { dg-warning "is deprecated: obsolete" } */
+  /* { dg-message "use .newtype. instead" "" { target *-*-* } .-1 } */
+  int i = oldvar; /* { dg-warning "is deprecated: unsafe" } */
+  /* { dg-message "use .newvar. instead" "" { target *-*-* } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c
index 044725e5123..6cb70705bbf 100644
--- a/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c
+++ b/gcc/testsuite/gcc.dg/c2x-attr-deprecated-3.c
@@ -6,6 +6,6 @@
 
 [[deprecated(0)]] int b; /* { dg-error "expected" } */
 
-[[deprecated("", 123)]] int c; /* { dg-error "expected" } */
+[[deprecated("", 123)]] int c; /* { dg-error "only allowed in GNU attributes" } */
 
 [[deprecated((""))]] int d; /* { dg-error "expected" } */
diff --git a/gcc/tree.c b/gcc/tree.c
index 561b9cd56bd..5cb2d57a960 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12002,8 +12002,9 @@ bool
 warn_deprecated_use (tree node, tree attr)
 {
   escaped_string msg;
+  escaped_string rep;
 
-  if (node == 0 || !warn_deprecated_decl)
+  if (node == NULL_TREE || !warn_deprecated_decl)
     return false;
 
   if (!attr)
@@ -12023,7 +12024,12 @@ warn_deprecated_use (tree node, tree attr)
     attr = lookup_attribute ("deprecated", attr);
 
   if (attr)
-    msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+    {
+      tree val = TREE_VALUE (attr);
+      msg.escape (TREE_STRING_POINTER (TREE_VALUE (val)));
+      if (TREE_CHAIN (val))
+	rep.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_CHAIN (val))));
+    }
 
   bool w = false;
   if (DECL_P (node))
@@ -12036,7 +12042,11 @@ warn_deprecated_use (tree node, tree attr)
 	w = warning (OPT_Wdeprecated_declarations,
 		     "%qD is deprecated", node);
       if (w)
-	inform (DECL_SOURCE_LOCATION (node), "declared here");
+	{
+	  if (rep)
+	    inform (input_location, "use %qs instead", (const char *) rep);
+	  inform (DECL_SOURCE_LOCATION (node), "declared here");
+	}
     }
   else if (TYPE_P (node))
     {
@@ -12072,8 +12082,13 @@ warn_deprecated_use (tree node, tree attr)
 			 "type is deprecated");
 	}
 
-      if (w && decl)
-	inform (DECL_SOURCE_LOCATION (decl), "declared here");
+      if (w)
+	{
+	  if (rep)
+	    inform (input_location, "use %qs instead", (const char *) rep);
+	  if (decl)
+	    inform (DECL_SOURCE_LOCATION (decl), "declared here");
+	}
     }
 
   return w;
