Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 278310)
+++ gcc/c/c-parser.c	(working copy)
@@ -4873,6 +4873,9 @@ c_parser_std_attribute (c_parser *parser)
 static tree
 c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
 {
+  bool seen_deprecated = false;
+  bool seen_fallthrough = false;
+  bool seen_maybe_unused = false;
   location_t loc = c_parser_peek_token (parser)->location;
   if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
     return NULL_TREE;
@@ -4898,8 +4901,55 @@ c_parser_std_attribute_specifier (c_parser *parser
       tree attribute = c_parser_std_attribute (parser);
       if (attribute != error_mark_node)
 	{
-	  TREE_CHAIN (attribute) = attributes;
-	  attributes = attribute;
+	  bool duplicate = false;
+	  tree name = get_attribute_name (attribute);
+	  tree ns = get_attribute_namespace (attribute);
+	  if (ns == NULL_TREE)
+	    {
+	      /* Some standard attributes may appear at most once in
+		 each attribute list.  Diagnose duplicates and remove
+		 them from the list to avoid subsequent diagnostics
+		 such as the more general one for multiple
+		 "fallthrough" attributes in the same place (including
+		 in separate attribute lists in the same attribute
+		 specifier sequence, which is not a constraint
+		 violation).  */
+	      if (is_attribute_p ("deprecated", name))
+		{
+		  if (seen_deprecated)
+		    {
+		      error ("attribute %<deprecated%> can appear at most "
+			     "once in an attribute-list");
+		      duplicate = true;
+		    }
+		  seen_deprecated = true;
+		}
+	      else if (is_attribute_p ("fallthrough", name))
+		{
+		  if (seen_fallthrough)
+		    {
+		      error ("attribute %<fallthrough%> can appear at most "
+			     "once in an attribute-list");
+		      duplicate = true;
+		    }
+		  seen_fallthrough = true;
+		}
+	      else if (is_attribute_p ("maybe_unused", name))
+		{
+		  if (seen_maybe_unused)
+		    {
+		      error ("attribute %<maybe_unused%> can appear at most "
+			     "once in an attribute-list");
+		      duplicate = true;
+		    }
+		  seen_maybe_unused = true;
+		}
+	    }
+	  if (!duplicate)
+	    {
+	      TREE_CHAIN (attribute) = attributes;
+	      attributes = attribute;
+	    }
 	}
       if (c_parser_next_token_is_not (parser, CPP_COMMA))
 	break;
Index: gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-deprecated-4.c	(working copy)
@@ -0,0 +1,13 @@
+/* Test C2x deprecated attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[deprecated, __deprecated__]] int a; /* { dg-error "can appear at most once" } */
+[[__deprecated__, deprecated("message")]] int b; /* { dg-error "can appear at most once" } */
+int c [[deprecated("message"), deprecated]]; /* { dg-error "can appear at most once" } */
+[[deprecated, deprecated]]; /* { dg-error "can appear at most once" } */
+/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */
+
+/* Separate attribute lists in the same attribute specifier sequence,
+   with the same attribute in them, are OK.  */
+[[deprecated]] [[deprecated]] int d [[deprecated]] [[deprecated]];
Index: gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-fallthrough-4.c	(working copy)
@@ -0,0 +1,23 @@
+/* Test C2x fallthrough attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int
+f (int a)
+{
+  switch (a)
+    {
+    case 1:
+      a++;
+      [[fallthrough, __fallthrough__]]; /* { dg-error "can appear at most once" } */
+    case 2:
+      a++;
+      /* Separate attribute lists in the same attribute specifier
+	 sequence, with the same attribute in them, are OK (but
+	 receive a warning).  */
+      [[fallthrough]] [[fallthrough]]; /* { dg-warning "specified multiple times" } */
+    case 3:
+      a++;
+    }
+  return a;
+}
Index: gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/c2x-attr-maybe_unused-4.c	(working copy)
@@ -0,0 +1,13 @@
+/* Test C2x maybe_unused attribute: duplicates.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[maybe_unused, __maybe_unused__]] int a; /* { dg-error "can appear at most once" } */
+[[__maybe_unused__, maybe_unused]] int b; /* { dg-error "can appear at most once" } */
+int c [[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */
+[[maybe_unused, maybe_unused]]; /* { dg-error "can appear at most once" } */
+/* { dg-warning "ignored" "ignored" { target *-*-* } .-1 } */
+
+/* Separate attribute lists in the same attribute specifier sequence,
+   with the same attribute in them, are OK.  */
+[[maybe_unused]] [[maybe_unused]] int d [[maybe_unused]] [[maybe_unused]];
