diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 4f9878d2695..ffe17eaa9d9 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -494,7 +494,8 @@ const struct c_common_resword c_common_reswords[] =
   { "typedef",		RID_TYPEDEF,	0 },
   { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
   { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
-  { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
+  { "typeof",		RID_TYPEOF,	D_EXT11 },
+  { "typeof_unqual",	RID_TYPEOF_UNQUAL,	D_CONLY | D_C2X },
   { "union",		RID_UNION,	0 },
   { "unsigned",		RID_UNSIGNED,	0 },
   { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5f470d94f4a..62ab4ba437b 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -104,7 +104,8 @@ enum rid
   RID_SIZEOF,
 
   /* C extensions */
-  RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
+  RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
+  RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	     RID_BUILTIN_SHUFFLE,
   RID_BUILTIN_SHUFFLEVECTOR,   RID_BUILTIN_CONVERTVECTOR,   RID_BUILTIN_TGMATH,
@@ -438,16 +439,17 @@ extern machine_mode c_default_pointer_mode;
 #define D_CXX11         0x0010	/* In C++, C++11 only.  */
 #define D_EXT		0x0020	/* GCC extension.  */
 #define D_EXT89		0x0040	/* GCC extension incorporated in C99.  */
-#define D_ASM		0x0080	/* Disabled by -fno-asm.  */
-#define D_OBJC		0x0100	/* In Objective C and neither C nor C++.  */
-#define D_CXX_OBJC	0x0200	/* In Objective C, and C++, but not C.  */
-#define D_CXXWARN	0x0400	/* In C warn with -Wcxx-compat.  */
-#define D_CXX_CONCEPTS  0x0800	/* In C++, only with concepts.  */
-#define D_TRANSMEM	0x1000	/* C++ transactional memory TS.  */
-#define D_CXX_CHAR8_T	0x2000	/* In C++, only with -fchar8_t.  */
-#define D_CXX20		0x4000  /* In C++, C++20 only.  */
-#define D_CXX_COROUTINES 0x8000  /* In C++, only with coroutines.  */
-#define D_CXX_MODULES	0x10000  /* In C++, only with modules.  */
+#define D_EXT11		0x0080	/* GCC extension incorporated in C2X.  */
+#define D_ASM		0x0100	/* Disabled by -fno-asm.  */
+#define D_OBJC		0x0200	/* In Objective C and neither C nor C++.  */
+#define D_CXX_OBJC	0x0400	/* In Objective C, and C++, but not C.  */
+#define D_CXXWARN	0x0800	/* In C warn with -Wcxx-compat.  */
+#define D_CXX_CONCEPTS  0x1000	/* In C++, only with concepts.  */
+#define D_TRANSMEM	0x2000	/* C++ transactional memory TS.  */
+#define D_CXX_CHAR8_T	0x4000	/* In C++, only with -fchar8_t.  */
+#define D_CXX20		0x8000  /* In C++, C++20 only.  */
+#define D_CXX_COROUTINES 0x10000  /* In C++, only with coroutines.  */
+#define D_CXX_MODULES	0x20000  /* In C++, only with modules.  */
 
 #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
 #define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index f6a94ba31d8..35fe6b4da81 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -127,6 +127,8 @@ c_parse_init (void)
       mask |= D_ASM | D_EXT;
       if (!flag_isoc99)
 	mask |= D_EXT89;
+      if (!flag_isoc2x)
+	mask |= D_EXT11;
     }
   if (!c_dialect_objc ())
     mask |= D_OBJC | D_CXX_OBJC;
@@ -580,6 +582,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_STRUCT:
     case RID_UNION:
     case RID_TYPEOF:
+    case RID_TYPEOF_UNQUAL:
     case RID_CONST:
     case RID_ATOMIC:
     case RID_VOLATILE:
@@ -757,6 +760,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_STRUCT:
 	case RID_UNION:
 	case RID_TYPEOF:
+	case RID_TYPEOF_UNQUAL:
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -3028,6 +3032,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_type (loc, specs, t);
 	  break;
 	case RID_TYPEOF:
+	case RID_TYPEOF_UNQUAL:
 	  /* ??? The old parser rejected typeof after other type
 	     specifiers, but is a syntax error the best way of
 	     handling this?  */
@@ -3715,22 +3720,38 @@ c_parser_struct_declaration (c_parser *parser)
   return decls;
 }
 
-/* Parse a typeof specifier (a GNU extension).
+/* Parse a typeof specifier (a GNU extension adopted in C2X).
 
    typeof-specifier:
      typeof ( expression )
      typeof ( type-name )
+     typeof_unqual ( expression )
+     typeof_unqual ( type-name )
 */
 
 static struct c_typespec
 c_parser_typeof_specifier (c_parser *parser)
 {
+  bool is_unqual;
+  bool is_std;
   struct c_typespec ret;
   ret.kind = ctsk_typeof;
   ret.spec = error_mark_node;
   ret.expr = NULL_TREE;
   ret.expr_const_operands = true;
-  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+  if (c_parser_next_token_is_keyword (parser, RID_TYPEOF))
+    {
+      is_unqual = false;
+      tree spelling = c_parser_peek_token (parser)->value;
+      is_std = (flag_isoc2x
+		&& strcmp (IDENTIFIER_POINTER (spelling), "typeof") == 0);
+    }
+  else
+    {
+      gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL));
+      is_unqual = true;
+      is_std = true;
+    }
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   in_typeof++;
@@ -3772,6 +3793,24 @@ c_parser_typeof_specifier (c_parser *parser)
       pop_maybe_used (was_vm);
     }
   parens.skip_until_found_close (parser);
+  if (ret.spec != error_mark_node)
+    {
+      if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+	ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+      if (is_std)
+	{
+	  /* In ISO C terms, _Noreturn is not part of the type of
+	     expressions such as &abort, but in GCC it is represented
+	     internally as a type qualifier.  */
+	  if (TREE_CODE (ret.spec) == FUNCTION_TYPE
+	      && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+	    ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+	  else if (FUNCTION_POINTER_TYPE_P (ret.spec)
+		   && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED)
+	    ret.spec
+	      = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec)));
+	}
+    }
   return ret;
 }
 
@@ -11866,7 +11905,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
      identifier
      one of
        enum struct union if else while do for switch case default
-       break continue return goto asm sizeof typeof __alignof
+       break continue return goto asm sizeof typeof typeof_unqual __alignof
        unsigned long const short volatile signed restrict _Complex
        in out inout bycopy byref oneway int char float double void _Bool
        _Atomic
@@ -11906,6 +11945,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_ASM:
     case RID_SIZEOF:
     case RID_TYPEOF:
+    case RID_TYPEOF_UNQUAL:
     case RID_ALIGNOF:
     case RID_UNSIGNED:
     case RID_LONG:
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ac242b5ed13..f9190680a3c 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3187,6 +3187,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 
   /* fntype now gets the type of function pointed to.  */
   fntype = TREE_TYPE (fntype);
+  tree return_type = TREE_TYPE (fntype);
 
   /* Convert the parameters to the types declared in the
      function prototype, or apply default promotions.  */
@@ -3203,8 +3204,6 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
       && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
       && !comptypes (fntype, TREE_TYPE (tem)))
     {
-      tree return_type = TREE_TYPE (fntype);
-
       /* This situation leads to run-time undefined behavior.  We can't,
 	 therefore, simply error unless we can prove that all possible
 	 executions of the program must execute the code.  */
@@ -3229,22 +3228,25 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   bool warned_p = check_function_arguments (loc, fundecl, fntype,
 					    nargs, argarray, &arg_loc);
 
+  if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED
+      && !VOID_TYPE_P (return_type))
+    return_type = c_build_qualified_type (return_type, TYPE_UNQUALIFIED);
   if (name != NULL_TREE
       && startswith (IDENTIFIER_POINTER (name), "__builtin_"))
     {
       if (require_constant_value)
 	result
-	  = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
+	  = fold_build_call_array_initializer_loc (loc, return_type,
 						   function, nargs, argarray);
       else
-	result = fold_build_call_array_loc (loc, TREE_TYPE (fntype),
+	result = fold_build_call_array_loc (loc, return_type,
 					    function, nargs, argarray);
       if (TREE_CODE (result) == NOP_EXPR
 	  && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
 	STRIP_TYPE_NOPS (result);
     }
   else
-    result = build_call_array_loc (loc, TREE_TYPE (fntype),
+    result = build_call_array_loc (loc, return_type,
 				   function, nargs, argarray);
   /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again
      later.  */
@@ -4831,6 +4833,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 	else
 	  val = build2 (code, TREE_TYPE (arg), arg, inc);
 	TREE_SIDE_EFFECTS (val) = 1;
+	if (TYPE_QUALS (TREE_TYPE (val)) != TYPE_UNQUALIFIED)
+	  TREE_TYPE (val) = c_build_qualified_type (TREE_TYPE (val),
+						    TYPE_UNQUALIFIED);
 	ret = val;
 	goto return_build_unary_op;
       }
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 0b121a91e1c..22d1ab92add 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -241,9 +241,9 @@ init_reswords (void)
   if (!flag_char8_t)
     mask |= D_CXX_CHAR8_T;
   if (flag_no_asm)
-    mask |= D_ASM | D_EXT;
+    mask |= D_ASM | D_EXT | D_EXT11;
   if (flag_no_gnu_keywords)
-    mask |= D_EXT;
+    mask |= D_EXT | D_EXT11;
 
   /* The Objective-C keywords are all context-dependent.  */
   mask |= D_OBJC;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e0c2c57c9b2..a2b0b9636f0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -2534,7 +2534,10 @@ this switch.  You may want to use the @option{-fno-gnu-keywords} flag
 instead, which disables @code{typeof} but not @code{asm} and
 @code{inline}.  In C99 mode (@option{-std=c99} or @option{-std=gnu99}),
 this switch only affects the @code{asm} and @code{typeof} keywords,
-since @code{inline} is a standard keyword in ISO C99.
+since @code{inline} is a standard keyword in ISO C99.  In C2X mode
+(@option{-std=c2x} or @option{-std=gnu2x}), this switch only affects
+the @code{asm} keyword, since @code{typeof} is a standard keyword in
+ISO C2X.
 
 @item -fno-builtin
 @itemx -fno-builtin-@var{function}
diff --git a/gcc/testsuite/gcc.dg/c11-typeof-1.c b/gcc/testsuite/gcc.dg/c11-typeof-1.c
new file mode 100644
index 00000000000..a2abe8e465c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-typeof-1.c
@@ -0,0 +1,6 @@
+/* Test typeof and typeof_unqual not keywords in C11.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-1.c b/gcc/testsuite/gcc.dg/c2x-typeof-1.c
new file mode 100644
index 00000000000..0b721fedd4c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-1.c
@@ -0,0 +1,208 @@
+/* Test C2x typeof and typeof_unqual.  Valid code.  */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int i;
+extern typeof (i) i;
+extern typeof (int) i;
+extern typeof_unqual (i) i;
+extern typeof_unqual (int) i;
+
+volatile int vi;
+extern typeof (volatile int) vi;
+extern typeof (vi) vi;
+
+extern typeof_unqual (volatile int) i;
+extern typeof_unqual (vi) i;
+extern typeof ((const int) vi) i;
+extern typeof ((volatile int) vi) i;
+
+const int ci;
+extern typeof (const int) ci;
+extern typeof (ci) ci;
+
+extern typeof_unqual (const int) i;
+extern typeof_unqual (ci) i;
+extern typeof ((const int) ci) i;
+extern typeof (+ci) i;
+extern typeof (0, ci) i;
+extern typeof (1 ? ci : ci) i;
+extern typeof (0) i;
+
+const int fci (void);
+extern typeof (fci ()) i;
+
+_Atomic int ai;
+extern typeof (_Atomic int) ai;
+extern typeof (_Atomic (int)) ai;
+extern typeof (ai) ai;
+
+extern typeof_unqual (_Atomic int) i;
+extern typeof_unqual (_Atomic (int)) i;
+extern typeof_unqual (ai) i;
+extern typeof (+ai) i;
+extern typeof ((_Atomic int) ai) i;
+extern typeof (0, ai) i;
+extern typeof (1 ? ai : ai) i;
+
+_Atomic int fai (void);
+extern typeof (fai ()) i;
+
+_Atomic const volatile int acvi;
+extern typeof (int volatile const _Atomic) acvi;
+extern typeof (acvi) acvi;
+extern const _Atomic volatile typeof (acvi) acvi;
+extern _Atomic volatile typeof (ci) acvi;
+extern _Atomic const typeof (vi) acvi;
+extern const typeof (ai) volatile acvi;
+
+extern typeof_unqual (acvi) i;
+extern typeof_unqual (typeof (acvi)) i;
+extern typeof_unqual (_Atomic typeof_unqual (acvi)) i;
+
+extern _Atomic typeof_unqual (acvi) ai;
+
+char c;
+volatile char vc;
+volatile char *pvc;
+volatile char *const cpvc;
+const char *pcc;
+const char *volatile vpcc;
+typeof (*vpcc) cc;
+
+extern typeof (*cpvc) vc;
+extern typeof_unqual (*cpvc) c;
+extern typeof_unqual (cpvc) pvc;
+extern typeof_unqual (vpcc) pcc;
+extern const char cc;
+
+extern typeof (++vi) i;
+extern typeof (++ai) i;
+extern typeof (--vi) i;
+extern typeof (--ai) i;
+extern typeof (vi++) i;
+extern typeof (ai++) i;
+extern typeof (vi--) i;
+extern typeof (ai--) i;
+
+bool b;
+volatile bool vb;
+_Atomic bool ab;
+extern typeof (++vb) b;
+extern typeof (++ab) b;
+extern typeof (--vb) b;
+extern typeof (--ab) b;
+extern typeof (vb++) b;
+extern typeof (ab++) b;
+extern typeof (vb--) b;
+extern typeof (ab--) b;
+
+extern typeof (vc = 1) c;
+extern typeof (vpcc = 0) pcc;
+extern typeof (ai *= 2) i;
+
+int s = sizeof (typeof (int (*)[++i]));
+
+void *vp;
+
+/* The non-returning property of a function is not part of the type given by
+   ISO C typeof.  */
+_Noreturn void nf1 (void);
+[[noreturn]] void nf2 (void);
+void fg (void) {}
+typeof (&nf1) pnf1 = fg;
+typeof (&nf2) pnf2 = fg;
+extern void (*pnf1) (void);
+extern void (*pnf2) (void);
+extern typeof (nf1) *pnf1;
+extern typeof (nf1) *pnf2;
+extern typeof (nf2) *pnf1;
+extern typeof (nf2) *pnf2;
+typeof (*&nf1) fg2, fg2a, fg2b;
+typeof (*&nf2) fg3, fg3a, fg3b;
+typeof (nf1) fg4, fg4a, fg4b;
+typeof (nf2) fg5, fg5a, fg5b;
+
+extern void abort (void);
+extern void exit (int);
+
+void fg2 (void) {}
+_Noreturn void fg2a (void) { abort (); }
+[[noreturn]] void fg2b (void) { abort (); }
+void fg3 (void) {}
+_Noreturn void fg3a (void) { abort (); }
+[[noreturn]] void fg3b (void) { abort (); }
+void fg4 (void) {}
+_Noreturn void fg4a (void) { abort (); }
+[[noreturn]] void fg4b (void) { abort (); }
+void fg5 (void) {}
+_Noreturn void fg5a (void) { abort (); }
+[[noreturn]] void fg5b (void) { abort (); }
+
+extern int only_used_in_typeof;
+
+static int not_defined (void);
+
+typeof (i)
+main (typeof (*vp))
+{
+  volatile typeof (only_used_in_typeof) ii = 2;
+  if (ii != 2)
+    abort ();
+  const typeof (not_defined ()) jj = 3;
+  if (jj != 3)
+    abort ();
+  unsigned int u = 1;
+  typeof (u) u2 = 0;
+  typeof (int (*)[++u2]) p = 0;
+  if (u2 != 1)
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  typeof_unqual (int (*)[++u2]) q = 0;
+  if (u2 != 2)
+    abort ();
+  if (sizeof (*q) != 2 * sizeof (int))
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  typeof (++u2) u3 = 1;
+  if (u2 != u + u3)
+    abort ();
+  typeof_unqual (++u2) u4 = 2;
+  if (u2 != u4)
+    abort ();
+  u = sizeof (typeof (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  u = sizeof (typeof_unqual (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  typeof ((int (*)[++u2]) 0) q2;
+  if (u2 != 3)
+    abort ();
+  typeof ((void) 0, (int (*)[++u2]) 0) q3;
+  if (u2 != 4)
+    abort ();
+  typeof ((int (*)[++u2]) 0, 0) q4;
+  if (u2 != 4)
+    abort ();
+  typeof_unqual ((int (*)[++u2]) 0) q5;
+  if (u2 != 5)
+    abort ();
+  typeof_unqual ((void) 0, (int (*)[++u2]) 0) q6;
+  if (u2 != 6)
+    abort ();
+  typeof_unqual ((int (*)[++u2]) 0, 0) q7;
+  if (u2 != 6)
+    abort ();
+  int a1[6], a2[6];
+  int (*pa)[u2] = &a1;
+  typeof (pa = &a2) pp;
+  if (pa != &a2)
+    abort ();
+  typeof_unqual (pa = &a1) pp2;
+  if (pa != &a1)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-2.c b/gcc/testsuite/gcc.dg/c2x-typeof-2.c
new file mode 100644
index 00000000000..f1c30a00a7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-2.c
@@ -0,0 +1,27 @@
+/* Test C2x typeof and typeof_unqual.  Invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+struct s { int i : 2; } x;
+union u { unsigned int j : 1; } y;
+
+typeof (x.i) j; /* { dg-error "applied to a bit-field" } */
+typeof_unqual (x.i) j2; /* { dg-error "applied to a bit-field" } */
+typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */
+typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */
+
+static int ok (void);
+static int also_ok (void);
+static int not_defined (void); /* { dg-error "used but never defined" } */
+static int also_not_defined (void); /* { dg-error "used but never defined" } */
+
+void
+f (void)
+{
+  typeof (ok ()) x = 2;
+  typeof_unqual (also_ok ()) y = 2;
+  int a[2];
+  int (*p)[x] = &a;
+  typeof (p + not_defined ()) q;
+  typeof_unqual (p + also_not_defined ()) q2;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-3.c b/gcc/testsuite/gcc.dg/c2x-typeof-3.c
new file mode 100644
index 00000000000..c7a057700d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-3.c
@@ -0,0 +1,7 @@
+/* Test C2x typeof and typeof_unqual.  -fno-asm has no effect on keywords in
+   C2x mode.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -fno-asm" } */
+
+int i;
+extern typeof (i) i;
diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-1.c b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c
new file mode 100644
index 00000000000..6477c78bd37
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c
@@ -0,0 +1,6 @@
+/* Test typeof and typeof_unqual not keywords with -std=gnu11 -fno-asm.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11 -fno-asm" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-2.c b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c
new file mode 100644
index 00000000000..e60ad466c37
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c
@@ -0,0 +1,39 @@
+/* Test typeof propagation of noreturn function attributes with -std=gnu11:
+   these are part of the type of a function pointer with GNU typeof, but not
+   with C2x typeof.  */
+/* { dg-do link } */
+/* { dg-options "-std=gnu11 -O2" } */
+
+_Noreturn void f (void);
+
+typeof (&f) volatile p;
+typeof (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+  (*p) ();
+  link_failure ();
+}
+
+void
+h (void)
+{
+  (**pp) ();
+  link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+  if (flag)
+    g ();
+  if (flag)
+    h ();
+  return x;
+}
diff --git a/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c
new file mode 100644
index 00000000000..f14b54f1f7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c
@@ -0,0 +1,39 @@
+/* Test __typeof__ propagation of noreturn function attributes with -std=gnu2x:
+   these are part of the type of a function pointer with GNU __typeof__, but
+   not with C2x typeof.  */
+/* { dg-do link } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+_Noreturn void f (void);
+
+__typeof__ (&f) volatile p;
+__typeof__ (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+  (*p) ();
+  link_failure ();
+}
+
+void
+h (void)
+{
+  (**pp) ();
+  link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+  if (flag)
+    g ();
+  if (flag)
+    h ();
+  return x;
+}
