public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] c: C2x noreturn attribute
@ 2022-09-29 23:00 Joseph Myers
  0 siblings, 0 replies; only message in thread
From: Joseph Myers @ 2022-09-29 23:00 UTC (permalink / raw)
  To: gcc-patches

C2x adds a standard [[noreturn]] attribute (which can also be spelt
[[_Noreturn]] for use with <stdnoreturn.h>), so allowing non-returning
functions to be declared in a manner compatible with C++; the
_Noreturn function specifier remains available but is marked
obsolescent.

Implement this attribute.  It's more restricted than GNU
__attribute__ ((noreturn)) - that allows function pointers but using
the standard attribute on a function pointer is a constraint
violation.  Thus, the attribute gets its own handler that checks for a
FUNCTION_DECL before calling the handler for the GNU attribute.  Tests
for the attribute are based on those for C11 _Noreturn and for other
C2x attributes.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c-family/
	* c-lex.cc (c_common_has_attribute): Handle noreturn attribute for
	C.

gcc/c/
	* c-decl.cc (handle_std_noreturn_attribute): New function.
	(std_attribute_table): Add _Noreturn and noreturn.

gcc/testsuite/
	* gcc.dg/c2x-attr-noreturn-1.c, gcc.dg/c2x-attr-noreturn-2.c,
	gcc.dg/c2x-attr-noreturn-3.c: New tests.
	* gcc.dg/c2x-has-c-attribute-2.c: Also test __has_c_attribute for
	noreturn attribute.

diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc
index 4d2252fd946..d4e448a0132 100644
--- a/gcc/c-family/c-lex.cc
+++ b/gcc/c-family/c-lex.cc
@@ -389,6 +389,9 @@ c_common_has_attribute (cpp_reader *pfile, bool std_syntax)
 		result = 202003;
 	      else if (is_attribute_p ("maybe_unused", attr_name))
 		result = 202106;
+	      else if (is_attribute_p ("noreturn", attr_name)
+		       || is_attribute_p ("_Noreturn", attr_name))
+		result = 202202;
 	    }
 	  if (result)
 	    attr_name = NULL_TREE;
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 740982eae31..bac8e6cc3f6 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -4480,11 +4480,34 @@ handle_nodiscard_attribute (tree *node, tree name, tree /*args*/,
     }
   return NULL_TREE;
 }
+
+/* Handle the standard [[noreturn]] attribute.  */
+
+static tree
+handle_std_noreturn_attribute (tree *node, tree name, tree args,
+			       int flags, bool *no_add_attrs)
+{
+  /* Unlike GNU __attribute__ ((noreturn)), the standard [[noreturn]]
+     only applies to functions, not function pointers.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    return handle_noreturn_attribute (node, name, args, flags, no_add_attrs);
+  else
+    {
+      pedwarn (input_location, OPT_Wattributes,
+	       "standard %qE attribute can only be applied to functions",
+	       name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+}
+
 /* Table of supported standard (C2x) attributes.  */
 const struct attribute_spec std_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
        affects_type_identity, handler, exclude } */
+  { "_Noreturn", 0, 0, false, false, false, false,
+    handle_std_noreturn_attribute, NULL },
   { "deprecated", 0, 1, false, false, false, false,
     handle_deprecated_attribute, NULL },
   { "fallthrough", 0, 0, false, false, false, false,
@@ -4493,6 +4516,8 @@ const struct attribute_spec std_attribute_table[] =
     handle_unused_attribute, NULL },
   { "nodiscard", 0, 1, false, false, false, false,
     handle_nodiscard_attribute, NULL },
+  { "noreturn", 0, 0, false, false, false, false,
+    handle_std_noreturn_attribute, NULL },
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-noreturn-1.c b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-1.c
new file mode 100644
index 00000000000..d903c09a9e5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-1.c
@@ -0,0 +1,56 @@
+/* Test C2x noreturn attribute: valid uses.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[noreturn]] void exit (int);
+
+[[__noreturn__]] int f1 (void);
+
+[[_Noreturn]] void f2 (void);
+
+[[___Noreturn__]] static void f3 (void) { exit (0); }
+
+/* Returning from a noreturn function is undefined at runtime, not a
+   constraint violation, but recommended practice is to diagnose if
+   such a return appears possible.  */
+
+[[noreturn]] int
+f4 (void)
+{
+  return 1; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } .-1 } */
+}
+
+[[__noreturn__]] void
+f5 (void)
+{
+  return; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } .-1 } */
+}
+
+[[_Noreturn]] void
+f6 (void)
+{
+} /* { dg-warning "does return" } */
+
+[[___Noreturn__]] void
+f7 (int a)
+{
+  if (a)
+    exit (0);
+} /* { dg-warning "does return" } */
+
+/* Declarations need not all have the attribute (buf if the first does not,
+   there is undefined behavior).  */
+
+void f2 (void);
+
+/* Duplicate attribute, and use with _Noreturn, is OK.  */
+[[noreturn]] [[noreturn]] [[noreturn, __noreturn__]] void _Noreturn f9 (void);
+
+/* The attribute does not affect type compatibility.  */
+
+void (*fp) (void) = f5;
+
+/* Unlike the function specifier, the attribute may be used on main.  */
+[[noreturn]] int main ();
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-noreturn-2.c b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-2.c
new file mode 100644
index 00000000000..331da4a6b5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-2.c
@@ -0,0 +1,72 @@
+/* Test C2x noreturn attribute: invalid contexts.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[noreturn]]; /* { dg-error "ignored" } */
+
+int [[noreturn]] var; /* { dg-error "ignored" } */
+
+int array_with_dep_type[2] [[noreturn]]; /* { dg-error "ignored" } */
+
+void fn_with_dep_type () [[noreturn]]; /* { dg-error "ignored" } */
+
+int z = sizeof (int [[__noreturn__]]); /* { dg-error "ignored" } */
+
+[[noreturn]] int x1; /* { dg-error "can only be applied to functions" } */
+int x2 [[__noreturn__]]; /* { dg-error "can only be applied to functions" } */
+
+[[_Noreturn]] void (*fp) (); /* { dg-error "can only be applied to functions" } */
+
+void
+f (void)
+{
+  int a;
+  [[_Noreturn]]; /* { dg-error "ignored" } */
+  [[___Noreturn__]] a = 1; /* { dg-error "ignored" } */
+}
+
+int
+g ([[noreturn]] int x, int y) /* { dg-error "can only be applied to functions" } */
+{
+  [[noreturn]] typedef float F; /* { dg-error "can only be applied to functions" } */
+  [[noreturn]] int a; /* { dg-error "can only be applied to functions" } */
+  int b [[__noreturn__]]; /* { dg-error "can only be applied to functions" } */
+  int c [[noreturn]]; /* { dg-error "can only be applied to functions" } */
+  [[__noreturn__]] label1: ; /* { dg-error "can only be applied to functions" } */
+  c = y;
+  [[noreturn]] label2: ; /* { dg-error "can only be applied to functions" } */
+  return y;
+}
+
+struct [[_Noreturn]] s { double d; }; /* { dg-error "can only be applied to functions" } */
+
+struct s2
+{
+  [[___Noreturn__]] int a; /* { dg-error "can only be applied to functions" } */
+  int b [[noreturn]]; /* { dg-error "can only be applied to functions" } */
+} x;
+
+enum e { E1 [[noreturn]] }; /* { dg-error "can only be applied to functions" } */
+
+union [[_Noreturn]] u { int x; }; /* { dg-error "can only be applied to functions" } */
+
+enum [[noreturn]] eu { E2 }; /* { dg-error "can only be applied to functions" } */
+
+void fx ([[noreturn]] int p); /* { dg-error "can only be applied" } */
+
+union u2
+{
+  [[noreturn]] int a; /* { dg-error "can only be applied to functions" } */
+  int b [[noreturn]]; /* { dg-error "can only be applied to functions" } */
+} y;
+
+void
+g2 (int x)
+{
+  switch (x)
+    {
+      [[noreturn]] case 1: ; /* { dg-error "can only be applied to functions" } */
+      [[__noreturn__]] case 2: ; /* { dg-error "can only be applied to functions" } */
+      [[noreturn]] default: ; /* { dg-error "can only be applied to functions" } */
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-attr-noreturn-3.c b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-3.c
new file mode 100644
index 00000000000..aaf21e22a13
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-attr-noreturn-3.c
@@ -0,0 +1,11 @@
+/* Test C2x noreturn attribute: invalid syntax.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+[[noreturn()]] void a(); /* { dg-error "does not take any arguments" } */
+
+[[__noreturn__(0)]] void b(); /* { dg-error "does not take any arguments|expected" } */
+
+[[_Noreturn("", 123)]] void c(); /* { dg-error "does not take any arguments|expected" } */
+
+[[___Noreturn__("")]] void d(); /* { dg-error "does not take any arguments|expected" } */
diff --git a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c
index 6a379e9db4f..3c34ab6cbd9 100644
--- a/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c
+++ b/gcc/testsuite/gcc.dg/c2x-has-c-attribute-2.c
@@ -34,6 +34,22 @@
 #error "bad result for __fallthrough__"
 #endif
 
+#if __has_c_attribute (noreturn) != 202202L
+#error "bad result for noreturn"
+#endif
+
+#if __has_c_attribute (__noreturn__) != 202202L
+#error "bad result for __noreturn__"
+#endif
+
+#if __has_c_attribute (_Noreturn) != 202202L
+#error "bad result for _Noreturn"
+#endif
+
+#if __has_c_attribute (___Noreturn__) != 202202L
+#error "bad result for ___Noreturn__"
+#endif
+  
 /* Macros in the attribute name are expanded.  */
 #define foo deprecated
 #if __has_c_attribute (foo) != 201904L

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-09-29 23:00 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-29 23:00 [committed] c: C2x noreturn attribute Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).