From b49184bea907db395a6102981e58230140984b48 Mon Sep 17 00:00:00 2001
From: TheShermanTanker <tanksherman27@gmail.com>
Date: Tue, 1 Aug 2023 11:07:03 +0800
Subject: [PATCH] Add the invalid-noreturn warning to match clang

---
 gcc/c-family/c.opt     |  8 ++++++++
 gcc/c/c-typeck.cc      |  9 ++++++---
 gcc/c/gimple-parser.cc |  9 ++++++---
 gcc/cp/coroutines.cc   | 11 +++++++----
 gcc/cp/typeck.cc       |  7 +++++--
 gcc/tree-cfg.cc        |  5 ++++-
 6 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 4abdc8d0e77..d12dca56e8b 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -478,6 +478,14 @@ Wc++23-extensions
 C++ ObjC++ Var(warn_cxx23_extensions) Warning Init(1)
 Warn about C++23 constructs in code compiled with an older standard.
 
+Winvalid-noreturn
+C ObjC C++ ObjC++ Warning Alias(Winvalid-noreturn=, 3, 0)
+Warn about code marked noreturn that actually returns.
+
+Winvalid-noreturn=
+C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_invalid_noreturn) Warning Init(3) IntegerRange(0, 3)
+Warn about code marked noreturn that actually returns.
+
 Wcast-function-type
 C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
 Warn about casts between incompatible function types.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7cf411155c6..2fbb2e29d52 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -11247,9 +11247,12 @@ c_finish_return (location_t loc, tree retval, tree origtype)
      in a function returning void.  */
   location_t xloc = expansion_point_location_if_in_system_header (loc);
 
-  if (TREE_THIS_VOLATILE (current_function_decl))
-    warning_at (xloc, 0,
-		"function declared %<noreturn%> has a %<return%> statement");
+  if (TREE_THIS_VOLATILE (current_function_decl)) {
+    if (warn_invalid_noreturn == 2 || warn_invalid_noreturn == 3) {
+      warning_at (xloc, 0,
+		  "function declared %<noreturn%> has a %<return%> statement");
+    }
+  }
 
   if (retval)
     {
diff --git a/gcc/c/gimple-parser.cc b/gcc/c/gimple-parser.cc
index cc3a8899d97..cfb7eed8277 100644
--- a/gcc/c/gimple-parser.cc
+++ b/gcc/c/gimple-parser.cc
@@ -2466,9 +2466,12 @@ c_finish_gimple_return (location_t loc, tree retval)
      in a function returning void.  */
   location_t xloc = expansion_point_location_if_in_system_header (loc);
 
-  if (TREE_THIS_VOLATILE (current_function_decl))
-    warning_at (xloc, 0,
-		"function declared %<noreturn%> has a %<return%> statement");
+  if (TREE_THIS_VOLATILE (current_function_decl)) {
+    if (warn_invalid_noreturn == 2 || warn_invalid_noreturn == 3) {
+      warning_at (xloc, OPT_Winvalid_noreturn_,
+		  "function declared %<noreturn%> has a %<return%> statement");
+    }
+  }
 
   if (! retval)
     current_function_returns_null = 1;
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 3493d3c6ed3..24fa7c5341b 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -1386,10 +1386,13 @@ finish_co_return_stmt (location_t kw, tree expr)
     }
 
   /* Makes no sense for a co-routine really. */
-  if (TREE_THIS_VOLATILE (current_function_decl))
-    warning_at (kw, 0,
-		"function declared %<noreturn%> has a"
-		" %<co_return%> statement");
+  if (TREE_THIS_VOLATILE (current_function_decl)) {
+    if (warn_invalid_noreturn == 2 || warn_invalid_noreturn == 3) {
+      warning_at (kw, OPT_Winvalid_noreturn_,
+		  "function declared %<noreturn%> has a"
+		  " %<co_return%> statement");
+    }
+  }
 
   expr = build2_loc (kw, CO_RETURN_EXPR, void_type_node, expr, co_ret_call);
   expr = maybe_cleanup_point_expr_void (expr);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 859b133a18d..4b32a089841 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -10939,8 +10939,11 @@ check_return_expr (tree retval, bool *no_warning)
   /* A `volatile' function is one that isn't supposed to return, ever.
      (This is a G++ extension, used to get better code for functions
      that call the `volatile' function.)  */
-  if (TREE_THIS_VOLATILE (current_function_decl))
-    warning (0, "function declared %<noreturn%> has a %<return%> statement");
+  if (TREE_THIS_VOLATILE (current_function_decl)) {
+    if (warn_invalid_noreturn == 2 || warn_invalid_noreturn == 3) {
+      warning (OPT_Winvalid_noreturn_, "function declared %<noreturn%> has a %<return%> statement");
+    }
+  }
 
   /* Check for various simple errors.  */
   if (DECL_DESTRUCTOR_P (current_function_decl))
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 7ccc2a5a5a7..99c10652810 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -9633,7 +9633,10 @@ pass_warn_function_return::execute (function *fun)
 	}
       if (location == UNKNOWN_LOCATION)
 	location = cfun->function_end_locus;
-      warning_at (location, 0, "%<noreturn%> function does return");
+
+      if (warn_invalid_noreturn == 1 || warn_invalid_noreturn == 3) {
+        warning_at (location, OPT_Winvalid_noreturn_, "%<noreturn%> function does return");
+      }
     }
 
   /* If we see "return;" in some basic block, then we do reach the end
-- 
2.35.1.windows.2

