c, c++: preserve type name in conversion [PR116060]

Message ID 20250109193341.4057416-1-jason@redhat.com
State New
Headers
Series c, c++: preserve type name in conversion [PR116060] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Jason Merrill Jan. 9, 2025, 7:32 p.m. UTC
  I spent way too long poking at various adjustments of this; here's what I
settled on for GCC 15.

Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

When the program requests a conversion to a typedef, let's try harder to
remember the new name.

Torbjörn's original patch changed the type of the original expression, but
that seems not generally desirable; we might want either or both of the
original type and the converted-to type to be represented.  So this
expresses the name change as a NOP_EXPR.

Compiling stdc++.h, this adds 519 allocations out of 1870k, or 0.28%.

The -Wsuggest-attribute=format change was necessary to do the check before
converting to the target type, which seems like an improvement.

	PR c/116060

gcc/c/ChangeLog:

	* c-typeck.cc (convert_for_assignment): Make sure left hand side and
	right hand side has identical named types to aid diagnostic output.

gcc/cp/ChangeLog:

	* call.cc (standard_conversion): Preserve type name in ck_identity.
	(maybe_adjust_type_name): New.
	(convert_like_internal): Use it.
	Handle -Wsuggest-attribute=format here.
	(convert_for_arg_passing): Not here.

gcc/testsuite/ChangeLog:

	* c-c++-common/analyzer/out-of-bounds-diagram-8.c: Update to
	correct type.
	* c-c++-common/analyzer/out-of-bounds-diagram-11.c: Likewise.
	* gcc.dg/analyzer/out-of-bounds-diagram-10.c: Likewise.

Co-authored-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
---
 gcc/c/c-typeck.cc                             |  3 +
 gcc/cp/call.cc                                | 68 ++++++++++++++-----
 .../analyzer/out-of-bounds-diagram-11.c       | 28 ++++----
 .../analyzer/out-of-bounds-diagram-8.c        | 28 ++++----
 .../analyzer/out-of-bounds-diagram-10.c       | 28 ++++----
 5 files changed, 96 insertions(+), 59 deletions(-)


base-commit: 04f4ac9218259a1508f9a86ca98cf1d36cab2df2
  

Patch

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index dbb688cabaa..6e40f7edf02 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7831,6 +7831,9 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
   if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
     {
       warn_for_address_of_packed_member (type, orig_rhs);
+      if (type != rhstype)
+	/* Convert RHS to TYPE in order to not lose TYPE in diagnostics.  */
+	rhs = convert (type, rhs);
       return rhs;
     }
 
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 5dbaec983f6..602f496e180 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -1319,6 +1319,9 @@  standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
     {
       if (CLASS_TYPE_P (to) && conv->kind == ck_rvalue)
 	conv->type = qualified_to;
+      else if (from != to)
+	/* Use TO in order to not lose TO in diagnostics.  */
+	conv->type = to;
       return conv;
     }
 
@@ -8486,6 +8489,37 @@  maybe_warn_array_conv (location_t loc, conversion *c, tree expr)
 static tree convert_like (conversion *, tree, tree, int, bool, bool, bool,
 			  tsubst_flags_t);
 
+/* Adjust the result EXPR of a conversion to the expected type TOTYPE, which
+   must be equivalent but might be a typedef.  */
+
+static tree
+maybe_adjust_type_name (tree type, tree expr, conversion_kind kind)
+{
+  if (expr == error_mark_node
+      || processing_template_decl)
+    return expr;
+
+  tree etype = TREE_TYPE (expr);
+  if (etype == type)
+    return expr;
+
+  gcc_checking_assert (same_type_ignoring_top_level_qualifiers_p (etype, type)
+		       || is_bitfield_expr_with_lowered_type (expr)
+		       || seen_error ());
+
+  if (SCALAR_TYPE_P (type)
+      && (kind == ck_rvalue
+	  /* ??? We should be able to do this for ck_identity of more prvalue
+	     expressions, but checking !obvalue_p here breaks, so for now let's
+	     just handle NON_LVALUE_EXPR (such as the location wrapper for a
+	     literal).  Maybe we want to express already-rvalue in the
+	     conversion somehow?  */
+	  || TREE_CODE (expr) == NON_LVALUE_EXPR))
+    expr = build_nop (type, expr);
+
+  return expr;
+}
+
 /* Perform the conversions in CONVS on the expression EXPR.  FN and
    ARGNUM are used for diagnostics.  ARGNUM is zero based, -1
    indicates the `this' argument of a method.  INNER is nonzero when
@@ -8747,7 +8781,7 @@  convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 	   continue to warn about uses of EXPR as an integer, rather than as a
 	   pointer.  */
 	expr = build_int_cst (totype, 0);
-      return expr;
+      return maybe_adjust_type_name (totype, expr, convs->kind);
     case ck_ambig:
       /* We leave bad_p off ck_ambig because overload resolution considers
 	 it valid, it just fails when we try to perform it.  So we need to
@@ -8885,8 +8919,22 @@  convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 	  return error_mark_node;
 	}
 
+      if ((complain & tf_warning) && fn
+	  && warn_suggest_attribute_format)
+	{
+	  tree rhstype = TREE_TYPE (expr);
+	  const enum tree_code coder = TREE_CODE (rhstype);
+	  const enum tree_code codel = TREE_CODE (totype);
+	  if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
+	      && coder == codel
+	      && check_missing_format_attribute (totype, rhstype))
+	    warning (OPT_Wsuggest_attribute_format,
+		     "argument of function call might be a candidate "
+		     "for a format attribute");
+	}
+
       if (! MAYBE_CLASS_TYPE_P (totype))
-	return expr;
+	return maybe_adjust_type_name (totype, expr, convs->kind);
 
       /* Don't introduce copies when passing arguments along to the inherited
 	 constructor.  */
@@ -9512,21 +9560,7 @@  convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
 	   && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
     val = cp_perform_integral_promotions (val, complain);
   if (complain & tf_warning)
-    {
-      if (warn_suggest_attribute_format)
-	{
-	  tree rhstype = TREE_TYPE (val);
-	  const enum tree_code coder = TREE_CODE (rhstype);
-	  const enum tree_code codel = TREE_CODE (type);
-	  if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
-	      && coder == codel
-	      && check_missing_format_attribute (type, rhstype))
-	    warning (OPT_Wsuggest_attribute_format,
-		     "argument of function call might be a candidate "
-		     "for a format attribute");
-	}
-      maybe_warn_parm_abi (type, cp_expr_loc_or_input_loc (val));
-    }
+    maybe_warn_parm_abi (type, cp_expr_loc_or_input_loc (val));
 
   if (complain & tf_warning)
     warn_for_address_of_packed_member (type, val);
diff --git a/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-11.c b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-11.c
index 63ae08347aa..048a1b9698f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-11.c
+++ b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-11.c
@@ -47,20 +47,20 @@  void test7 (size_t size)
 
 /* { dg-begin-multiline-output "" }
 
-                                 ┌───────────────────────────────────────┐
-                                 │          write of '(int) 42'          │
-                                 └───────────────────────────────────────┘
-                                           │                   │
-                                           │                   │
-                                           v                   v
-  ┌──────────────────────────────────────────────────┐┌──────────────────┐
-  │         buffer allocated on stack at (1)         ││after valid range │
-  └──────────────────────────────────────────────────┘└──────────────────┘
-  ├────────────────────────┬─────────────────────────┤├────────┬─────────┤
-                           │                                   │
-          ╭────────────────┴───────────────╮         ╭─────────┴────────╮
-          │capacity: '(size * 4) + 3' bytes│         │overflow of 1 byte│
-          ╰────────────────────────────────╯         ╰──────────────────╯
+                                ┌────────────────────────────────────────┐
+                                │        write of '(int32_t) 42'         │
+                                └────────────────────────────────────────┘
+                                         │                     │
+                                         │                     │
+                                         v                     v
+  ┌────────────────────────────────────────────────┐ ┌───────────────────┐
+  │        buffer allocated on stack at (1)        │ │ after valid range │
+  └────────────────────────────────────────────────┘ └───────────────────┘
+  ├───────────────────────┬────────────────────────┤ ├─────────┬─────────┤
+                          │                                    │
+         ╭────────────────┴───────────────╮          ╭─────────┴────────╮
+         │capacity: '(size * 4) + 3' bytes│          │overflow of 1 byte│
+         ╰────────────────────────────────╯          ╰──────────────────╯
 
    { dg-end-multiline-output "" } */
 
diff --git a/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-8.c b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-8.c
index c8ff2fd1e64..4d1f5227049 100644
--- a/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-8.c
+++ b/gcc/testsuite/c-c++-common/analyzer/out-of-bounds-diagram-8.c
@@ -18,19 +18,19 @@  void test2 (size_t size)
 
 /* { dg-begin-multiline-output "" }
 
-                                                     ┌───────────────────┐
-                                                     │write of '(int) 42'│
-                                                     └───────────────────┘
-                                                               │
-                                                               │
-                                                               v
-  ┌───────────────────────────────┐                  ┌───────────────────┐
-  │buffer allocated on heap at (1)│                  │ after valid range │
-  └───────────────────────────────┘                  └───────────────────┘
-  ├───────────────┬───────────────┤├───────┬────────┤├─────────┬─────────┤
-                  │                        │                   │
-    ╭─────────────┴────────────╮       ╭───┴───╮     ╭─────────┴─────────╮
-    │capacity: 'size * 4' bytes│       │4 bytes│     │overflow of 4 bytes│
-    ╰──────────────────────────╯       ╰───────╯     ╰───────────────────╯
+                                                 ┌───────────────────────┐
+                                                 │write of '(int32_t) 42'│
+                                                 └───────────────────────┘
+                                                             │
+                                                             │
+                                                             v
+  ┌───────────────────────────────┐              ┌───────────────────────┐
+  │buffer allocated on heap at (1)│              │   after valid range   │
+  └───────────────────────────────┘              └───────────────────────┘
+  ├───────────────┬───────────────┤├─────┬──────┤├───────────┬───────────┤
+                  │                      │                   │
+    ╭─────────────┴────────────╮     ╭───┴───╮     ╭─────────┴─────────╮
+    │capacity: 'size * 4' bytes│     │4 bytes│     │overflow of 4 bytes│
+    ╰──────────────────────────╯     ╰───────╯     ╰───────────────────╯
 
    { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-10.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-10.c
index 4a7b8e306de..f719c4801dd 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-10.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-diagram-10.c
@@ -11,19 +11,19 @@  int32_t int_vla_write_element_symbolic_before_start (int32_t x, size_t n)
 
 /* { dg-begin-multiline-output "" }
 
-  ┌───────────────────┐
-  │write of '(int) 42'│
-  └───────────────────┘
-            │
-            │
-            v
-  ┌───────────────────┐                 ┌────────────────────────────────┐
-  │before valid range │                 │buffer allocated on stack at (1)│
-  └───────────────────┘                 └────────────────────────────────┘
-  ├─────────┬─────────┤├───────┬───────┤├───────────────┬────────────────┤
-            │                  │                        │
-  ╭─────────┴───────────╮  ╭───┴───╮        ╭───────────┴───────────╮
-  │underwrite of 4 bytes│  │4 bytes│        │capacity: 'n * 4' bytes│
-  ╰─────────────────────╯  ╰───────╯        ╰───────────────────────╯
+  ┌───────────────────────┐
+  │write of '(int32_t) 42'│
+  └───────────────────────┘
+              │
+              │
+              v
+  ┌───────────────────────┐             ┌────────────────────────────────┐
+  │  before valid range   │             │buffer allocated on stack at (1)│
+  └───────────────────────┘             └────────────────────────────────┘
+  ├───────────┬───────────┤├─────┬─────┤├───────────────┬────────────────┤
+              │                  │                      │
+   ╭──────────┴──────────╮   ╭───┴───╮      ╭───────────┴───────────╮
+   │underwrite of 4 bytes│   │4 bytes│      │capacity: 'n * 4' bytes│
+   ╰─────────────────────╯   ╰───────╯      ╰───────────────────────╯
 
    { dg-end-multiline-output "" } */