Add fix-it hint for missing return statement in assignment operators (PR c++/85523)
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 3 Aug 2018 18:38:13 +0000 (18:38 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 3 Aug 2018 18:38:13 +0000 (18:38 +0000)
gcc/cp/ChangeLog:

PR c++/85523
* decl.c: Include "gcc-rich-location.h".
(add_return_star_this_fixit): New function.
(finish_function): When warning about missing return statements in
functions returning non-void, add a "return *this;" fix-it hint for
assignment operators.

gcc/testsuite/ChangeLog:

PR c++/85523
* g++.dg/pr85523.C: New test.

Co-Authored-By: Jonathan Wakely <jwakely@redhat.com>
From-SVN: r263298

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr85523.C [new file with mode: 0644]

index 17f9821b939961141bab8164cf0d758e5a7622de..90af73d48102bb312b1d11cba000fbd88e377ca2 100644 (file)
@@ -1,3 +1,12 @@
+2018-08-03  David Malcolm  <dmalcolm@redhat.com>
+           Jonathan Wakely  <jwakely@redhat.com>
+
+       * decl.c: Include "gcc-rich-location.h".
+       (add_return_star_this_fixit): New function.
+       (finish_function): When warning about missing return statements in
+       functions returning non-void, add a "return *this;" fix-it hint for
+       assignment operators.
+
 2018-08-03  Jason Merrill  <jason@redhat.com>
 
        PR c++/86706
index 1206ddb3abe47d047ecc19bb1875bcc154f2a716..cf216a1a960c22a8c5d628f66c6a5a298604668c 100644 (file)
@@ -15710,6 +15710,22 @@ maybe_save_function_definition (tree fun)
     register_constexpr_fundef (fun, DECL_SAVED_TREE (fun));
 }
 
+/* Attempt to add a fix-it hint to RICHLOC suggesting the insertion
+   of "return *this;" immediately before its location, using FNDECL's
+   first statement (if any) to give the indentation, if appropriate.  */
+
+static void
+add_return_star_this_fixit (gcc_rich_location *richloc, tree fndecl)
+{
+  location_t indent = UNKNOWN_LOCATION;
+  tree stmts = expr_first (DECL_SAVED_TREE (fndecl));
+  if (stmts)
+    indent = EXPR_LOCATION (stmts);
+  richloc->add_fixit_insert_formatted ("return *this;",
+                                      richloc->get_loc (),
+                                      indent);
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition. INLINE_P is TRUE if we just
@@ -15903,8 +15919,21 @@ finish_function (bool inline_p)
       && !DECL_DESTRUCTOR_P (fndecl)
       && targetm.warn_func_return (fndecl))
     {
-      warning (OPT_Wreturn_type,
-              "no return statement in function returning non-void");
+      gcc_rich_location richloc (input_location);
+      /* Potentially add a "return *this;" fix-it hint for
+        assignment operators.  */
+      if (IDENTIFIER_ASSIGN_OP_P (DECL_NAME (fndecl)))
+       {
+         tree valtype = TREE_TYPE (DECL_RESULT (fndecl));
+         if (TREE_CODE (valtype) == REFERENCE_TYPE
+             && same_type_ignoring_top_level_qualifiers_p
+                 (TREE_TYPE (valtype), TREE_TYPE (current_class_ref)))
+           if (global_dc->option_enabled (OPT_Wreturn_type,
+                                          global_dc->option_state))
+             add_return_star_this_fixit (&richloc, fndecl);
+       }
+      warning_at (&richloc, OPT_Wreturn_type,
+                 "no return statement in function returning non-void");
       TREE_NO_WARNING (fndecl) = 1;
     }
 
index ba0c4c6ef5dff572cda798d53a2ec36b8a27a88a..0b61339a0b426343a9dbded2be9e17942b6f4eca 100644 (file)
@@ -1,3 +1,9 @@
+2018-08-03  David Malcolm  <dmalcolm@redhat.com>
+           Jonathan Wakely  <jwakely@redhat.com>
+
+       PR c++/85523
+       * g++.dg/pr85523.C: New test.
+
 2018-08-03  Bogdan Harjoc  <harjoc@gmail.com>
 
        PR c/86690
diff --git a/gcc/testsuite/g++.dg/pr85523.C b/gcc/testsuite/g++.dg/pr85523.C
new file mode 100644 (file)
index 0000000..9cd939b
--- /dev/null
@@ -0,0 +1,88 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* Verify that we emit a "return *this;" fix-it hint for
+   a missing return in an assignment operator.  */
+
+struct s1 {
+  s1& operator=(const s1&) { } // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
+   s1& operator=(const s1&) { }
+                              ^
+                              return *this;
+     { dg-end-multiline-output "" } */
+};
+
+/* Likewise for +=.  */
+
+struct s2 {
+  s2& operator+=(const s2&) {} // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
+   s2& operator+=(const s2&) {}
+                              ^
+                              return *this;
+     { dg-end-multiline-output "" } */
+};
+
+/* No warning for "void" return.  */
+
+struct s3 {
+  void operator=(const s3&) { }
+};
+
+/* We shouldn't issue the fix-it hint if the return type isn't right.  */
+
+struct s4 {
+  int operator=(int) { } // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
+   int operator=(int) { }
+                        ^
+     { dg-end-multiline-output "" } */
+};
+
+/* Example of a multi-line fix-it hint.  */
+
+struct s5 {
+  int i;
+  s5& operator=(const s5& z) {
+    i = z.i;
+  } // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
++    return *this;
+   }
+   ^
+     { dg-end-multiline-output "" } */
+};
+
+/* Example of a multi-line fix-it hint with other statements.  */
+
+extern void log (const char *);
+struct s6 {
+  int i;
+  s6& operator=(const s6& z) {
+    log ("operator=\n");
+    i = z.i;
+  } // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
++    return *this;
+   }
+   ^
+     { dg-end-multiline-output "" } */
+};
+
+/* Another example of a multi-line fix-it hint with other statements.  */
+
+struct s7 {
+  int i;
+  s7& operator=(const s6& z) {
+    if (z.i)
+      log ("operator=\n");
+    else
+      log ("operator=\n");
+    i = z.i;
+  } // { dg-warning "no return statement in function returning non-void" }
+  /* { dg-begin-multiline-output "" }
++    return *this;
+   }
+   ^
+     { dg-end-multiline-output "" } */
+};