This patch adds warning option -Wstring-plus-char for C/C++.

gcc/ChangeLog:

2017-06-12  Xi Ruoyao  <r...@stu.xidian.edu.cn>

        * c-family/c-common.h (warn_if_string_plus_char): New prototype.
        * c-family/c-warn.c (warn_if_string_plus_char): New function.
        * c-family/c.opt: New option -Wstring-plus-char.
        * cp/call.c (build_new_op_1): Check for -Wstring-plus-char.
        * c/c-typeck.c (parser_build_binary_op, build_modify_expr):
        Check for -Wstring-plus-char.
---
 gcc/c-family/c-common.h |  1 +
 gcc/c-family/c-warn.c   | 22 ++++++++++++++++++++++
 gcc/c-family/c.opt      |  5 +++++
 gcc/c/c-typeck.c        | 14 ++++++++++++++
 gcc/cp/call.c           | 28 ++++++++++++++++++++++++++++
 5 files changed, 70 insertions(+)

-- 
Xi Ruoyao <r...@stu.xidian.edu.cn>
School of Aerospace Science and Technology, Xidian University
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 82ed4f6..82f1c25 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1501,6 +1501,7 @@ extern void c_do_switch_warnings (splay_tree, location_t, tree, tree, bool,
 				  bool);
 extern void warn_for_omitted_condop (location_t, tree);
 extern void warn_for_restrict (unsigned, tree *, unsigned);
+extern void warn_if_string_plus_char (location_t, tree, tree);
 
 /* Places where an lvalue, or modifiable lvalue, may be required.
    Used to select diagnostic messages in lvalue_error and
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 35321a6..d804500 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2332,6 +2332,28 @@ warn_for_restrict (unsigned param_pos, tree *argarray, unsigned nargs)
 			 arg_positions.length ());
 }
 
+/* Like char_type_p, but check the main variant and filter out
+   char16_t (uint_least16_t) and char32_t (uint_least32_t) in C11.  */
+static inline bool
+type_main_variant_is_char (tree type)
+{
+  type = TYPE_MAIN_VARIANT (type);
+  return char_type_p (type)
+         && type != uint_least16_type_node
+         && type != uint_least32_type_node;
+}
+
+void
+warn_if_string_plus_char (location_t loc, tree ptrtype, tree inttype)
+{
+  if (POINTER_TYPE_P (ptrtype)
+      && type_main_variant_is_char (TREE_TYPE (ptrtype))
+      && type_main_variant_is_char (inttype))
+    warning_at (loc, OPT_Wstring_plus_char,
+                "add %qT to string pointer %qT does not append "
+                "to the string", inttype, ptrtype);
+}
+
 /* Callback function to determine whether an expression TP or one of its
    subexpressions comes from macro expansion.  Used to suppress bogus
    warnings.  */
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 94ba3eb..e13cc6c 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -732,6 +732,11 @@ C ObjC C++ ObjC++ Joined RejectNegative UInteger Var(warn_stringop_overflow) Ini
 Under the control of Object Size type, warn about buffer overflow in string
 manipulation functions like memcpy and strcpy.
 
+Wstring-plus-char
+C ObjC C++ ObjC++ Var(warn_string_plus_char) Warning
+Warn about adding string pointers and characters, which is likely an
+ill-formed attempt to append the string.
+
 Wstring-plus-int
 C ObjC C++ ObjC++ Var(warn_string_plus_int) Warning
 Warn about adding strings and integers, which is likely an ill-formed
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 8adfa9a..44e7e02 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3659,6 +3659,12 @@ parser_build_binary_op (location_t location, enum tree_code code,
 			   arg1.get_start (),
 			   arg2.get_finish ());
 
+  if (warn_string_plus_char && code == PLUS_EXPR)
+    {
+      warn_if_string_plus_char (location, type1, type2);
+      warn_if_string_plus_char (location, type2, type1);
+    }
+
   /* Check for cases such as x+y<<z which users are likely
      to misinterpret.  */
   if (warn_parentheses)
@@ -5788,6 +5794,14 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
 	  newrhs = build_binary_op (location,
 				    modifycode, lhs, newrhs, 1);
 
+	  if (warn_string_plus_char)
+	    {
+	      tree lt = (lhs_origtype ? lhs_origtype : TREE_TYPE (lhs));
+	      tree rt = (rhs_origtype ? rhs_origtype : TREE_TYPE (rhs));
+	      warn_if_string_plus_char (location, lt, rt);
+	      warn_if_string_plus_char (location, rt, lt);
+	    }
+
 	  /* The original type of the right hand side is no longer
 	     meaningful.  */
 	  rhs_origtype = NULL_TREE;
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ef99683..8e5ce6a 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5586,6 +5586,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
   enum tree_code code2 = NOP_EXPR;
   enum tree_code code_orig_arg1 = ERROR_MARK;
   enum tree_code code_orig_arg2 = ERROR_MARK;
+  tree orig_type1 = error_mark_node;
+  tree orig_type2 = error_mark_node;
   conversion *conv;
   void *p;
   bool strict_p;
@@ -5642,6 +5644,12 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 
       /* =, ->, [], () must be non-static member functions.  */
     case MODIFY_EXPR:
+      if (code2 == PLUS_EXPR)
+        {
+          /* Saved for warn_if_string_plus_char.  */
+          orig_type1 = TREE_TYPE (arg1);
+          orig_type2 = TREE_TYPE (arg2);
+        }
       if (code2 != NOP_EXPR)
 	break;
       /* FALLTHRU */
@@ -5649,6 +5657,11 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     case ARRAY_REF:
       memonly = true;
       break;
+    case PLUS_EXPR:
+      /* Saved for warn_if_string_plus_char.  */
+      orig_type1 = TREE_TYPE (arg1);
+      orig_type2 = TREE_TYPE (arg2);
+      break;
 
     default:
       break;
@@ -5977,6 +5990,13 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
   switch (code)
     {
     case MODIFY_EXPR:
+      if (code2 == PLUS_EXPR
+          && (complain & tf_warning)
+          && warn_string_plus_char)
+        {
+          warn_if_string_plus_char (loc, TREE_TYPE (arg1), orig_type2);
+          warn_if_string_plus_char (loc, TREE_TYPE (arg2), orig_type2);
+        }
       return cp_build_modify_expr (loc, arg1, code2, arg2, complain);
 
     case INDIRECT_REF:
@@ -6016,6 +6036,14 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
+      if ((complain & tf_warning)
+          && warn_string_plus_char
+          && code == PLUS_EXPR)
+        {
+          warn_if_string_plus_char (loc, TREE_TYPE (arg1), orig_type2);
+          warn_if_string_plus_char (loc, TREE_TYPE (arg2), orig_type1);
+        }
+
       return cp_build_binary_op (loc, code, arg1, arg2, complain);
 
     case UNARY_PLUS_EXPR:
-- 
2.7.1

Reply via email to