public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)
@ 2020-12-08 20:46 Martin Sebor
  2020-12-08 21:29 ` Martin Sebor
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Martin Sebor @ 2020-12-08 20:46 UTC (permalink / raw)
  To: gcc-patches, Jeff Law

[-- Attachment #1: Type: text/plain, Size: 1738 bytes --]

PR 98160 reports an ICE in pretty printer code called from the newly
added -Wmismatched-new-delete.  The ICE is just a simple oversight,
but much more interesting is the warning issued for the test case.
It highlights an issue I didn't consider in the initial implementation:
that inlining one of a pair of allocation/deallocation functions but
not the other might lead to false positives when the inlined function
calls another allocator that the deallocator isn't associated with.

In addition, tests for the changes exposed the overly simplistic
nature of the detection of calls to mismatched forms of operator
new and delete which fails to consider member operators, also
resulting in false positives.

Finally, in a comment on the initial implementation Jonathan notes
that the -Wmismatched-new-delete warning should trigger not only
in user code but also in libstdc++ functions inlined into user code.
I thought I had done that but as it turns out, the "standard code
sequence" I put in place isn't sufficient to make this work.

The attached changes avoid the false positives a) by ignoring (with
a warning) the new form of the malloc attribute on inline functions,
and disabling the inlining of others by implicitly adding attribute
noinline to their declaration, and b) by making more robust
the detection of mismatched operators new and delete.  Furthermore,
the patch also arranges for the warning to trigger even for inlined
calls to functions defined in system headers.

To make review a little (marginally) easier the change are two files:
1) gcc-98166-1.diff: introduces valid_new_delete_pair_p and
tree_inlined_location.
2) gcc-98166-2.diff: adjusts the atrribute/warning implementation .

Tested on x86_64-linux.

Martin

[-- Attachment #2: gcc-98166-1.diff --]
[-- Type: text/x-patch, Size: 8265 bytes --]

Introduce an overload of valid_new_delete_pair_p and tree_inlined_location.

gcc/ChangeLog:

	* tree-ssa-dce.c (valid_new_delete_pair_p): Factor code out into
	valid_new_delete_pair_p in tree.c.
	* tree.c (tree_inlined_location): Define new function.
	(valid_new_delete_pair_p): Define.
	* tree.h (tree_inlined_location): Declare.
	(valid_new_delete_pair_p): Declare.

diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index 9fb156c120d..5ec872967b7 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -656,67 +656,7 @@ valid_new_delete_pair_p (gimple *new_call, gimple *delete_call)
 {
   tree new_asm = DECL_ASSEMBLER_NAME (gimple_call_fndecl (new_call));
   tree delete_asm = DECL_ASSEMBLER_NAME (gimple_call_fndecl (delete_call));
-  const char *new_name = IDENTIFIER_POINTER (new_asm);
-  const char *delete_name = IDENTIFIER_POINTER (delete_asm);
-  unsigned int new_len = IDENTIFIER_LENGTH (new_asm);
-  unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm);
-
-  if (new_len < 5 || delete_len < 6)
-    return false;
-  if (new_name[0] == '_')
-    ++new_name, --new_len;
-  if (new_name[0] == '_')
-    ++new_name, --new_len;
-  if (delete_name[0] == '_')
-    ++delete_name, --delete_len;
-  if (delete_name[0] == '_')
-    ++delete_name, --delete_len;
-  if (new_len < 4 || delete_len < 5)
-    return false;
-  /* *_len is now just the length after initial underscores.  */
-  if (new_name[0] != 'Z' || new_name[1] != 'n')
-    return false;
-  if (delete_name[0] != 'Z' || delete_name[1] != 'd')
-    return false;
-  /* _Znw must match _Zdl, _Zna must match _Zda.  */
-  if ((new_name[2] != 'w' || delete_name[2] != 'l')
-      && (new_name[2] != 'a' || delete_name[2] != 'a'))
-    return false;
-  /* 'j', 'm' and 'y' correspond to size_t.  */
-  if (new_name[3] != 'j' && new_name[3] != 'm' && new_name[3] != 'y')
-    return false;
-  if (delete_name[3] != 'P' || delete_name[4] != 'v')
-    return false;
-  if (new_len == 4
-      || (new_len == 18 && !memcmp (new_name + 4, "RKSt9nothrow_t", 14)))
-    {
-      /* _ZnXY or _ZnXYRKSt9nothrow_t matches
-	 _ZdXPv, _ZdXPvY and _ZdXPvRKSt9nothrow_t.  */
-      if (delete_len == 5)
-	return true;
-      if (delete_len == 6 && delete_name[5] == new_name[3])
-	return true;
-      if (delete_len == 19 && !memcmp (delete_name + 5, "RKSt9nothrow_t", 14))
-	return true;
-    }
-  else if ((new_len == 19 && !memcmp (new_name + 4, "St11align_val_t", 15))
-	   || (new_len == 33
-	       && !memcmp (new_name + 4, "St11align_val_tRKSt9nothrow_t", 29)))
-    {
-      /* _ZnXYSt11align_val_t or _ZnXYSt11align_val_tRKSt9nothrow_t matches
-	 _ZdXPvSt11align_val_t or _ZdXPvYSt11align_val_t or  or
-	 _ZdXPvSt11align_val_tRKSt9nothrow_t.  */
-      if (delete_len == 20 && !memcmp (delete_name + 5, "St11align_val_t", 15))
-	return true;
-      if (delete_len == 21
-	  && delete_name[5] == new_name[3]
-	  && !memcmp (delete_name + 6, "St11align_val_t", 15))
-	return true;
-      if (delete_len == 34
-	  && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29))
-	return true;
-    }
-  return false;
+  return valid_new_delete_pair_p (new_asm, delete_asm);
 }
 
 /* Propagate necessity using the operands of necessary statements.
diff --git a/gcc/tree.c b/gcc/tree.c
index 02ce5ddcd49..6d2b217fcf4 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -12610,8 +12610,40 @@ tree_nonartificial_location (tree exp)
     return EXPR_LOCATION (exp);
 }
 
+/* Return the location into which EXP has been inlined.  Analogous
+   to tree_nonartificial_location() above but not limited to artificial
+   functions declared inline.  If SYSTEM_HEADER is true, return
+   the macro expansion point of the location if it's in a system header */
 
-/* These are the hash table functions for the hash table of OPTIMIZATION_NODEq
+location_t
+tree_inlined_location (tree exp, bool system_header /* = true */)
+{
+  location_t loc = UNKNOWN_LOCATION;
+
+  tree block = TREE_BLOCK (exp);
+
+  while (block && TREE_CODE (block) == BLOCK
+	 && BLOCK_ABSTRACT_ORIGIN (block))
+    {
+      tree ao = BLOCK_ABSTRACT_ORIGIN (block);
+      if (TREE_CODE (ao) == FUNCTION_DECL)
+	loc = BLOCK_SOURCE_LOCATION (block);
+      else if (TREE_CODE (ao) != BLOCK)
+	break;
+
+      block = BLOCK_SUPERCONTEXT (block);
+    }
+
+  if (loc == UNKNOWN_LOCATION)
+    loc = EXPR_LOCATION (exp);
+
+  if (system_header)
+    return expansion_point_location_if_in_system_header (loc);
+
+  return loc;
+}
+
+/* These are the hash table functions for the hash table of OPTIMIZATION_NODE
    nodes.  */
 
 /* Return the hash code X, an OPTIMIZATION_NODE or TARGET_OPTION code.  */
@@ -15386,6 +15418,75 @@ verify_type_context (location_t loc, type_context_kind context,
 	  || targetm.verify_type_context (loc, context, type, silent_p));
 }
 
+/* Return that NEW_ASM and DELETE_ASM name a valid pair of new and
+   delete operators.  */
+
+bool
+valid_new_delete_pair_p (tree new_asm, tree delete_asm)
+{
+  const char *new_name = IDENTIFIER_POINTER (new_asm);
+  const char *delete_name = IDENTIFIER_POINTER (delete_asm);
+  unsigned int new_len = IDENTIFIER_LENGTH (new_asm);
+  unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm);
+
+  if (new_len < 5 || delete_len < 6)
+    return false;
+  if (new_name[0] == '_')
+    ++new_name, --new_len;
+  if (new_name[0] == '_')
+    ++new_name, --new_len;
+  if (delete_name[0] == '_')
+    ++delete_name, --delete_len;
+  if (delete_name[0] == '_')
+    ++delete_name, --delete_len;
+  if (new_len < 4 || delete_len < 5)
+    return false;
+  /* *_len is now just the length after initial underscores.  */
+  if (new_name[0] != 'Z' || new_name[1] != 'n')
+    return false;
+  if (delete_name[0] != 'Z' || delete_name[1] != 'd')
+    return false;
+  /* _Znw must match _Zdl, _Zna must match _Zda.  */
+  if ((new_name[2] != 'w' || delete_name[2] != 'l')
+      && (new_name[2] != 'a' || delete_name[2] != 'a'))
+    return false;
+  /* 'j', 'm' and 'y' correspond to size_t.  */
+  if (new_name[3] != 'j' && new_name[3] != 'm' && new_name[3] != 'y')
+    return false;
+  if (delete_name[3] != 'P' || delete_name[4] != 'v')
+    return false;
+  if (new_len == 4
+      || (new_len == 18 && !memcmp (new_name + 4, "RKSt9nothrow_t", 14)))
+    {
+      /* _ZnXY or _ZnXYRKSt9nothrow_t matches
+	 _ZdXPv, _ZdXPvY and _ZdXPvRKSt9nothrow_t.  */
+      if (delete_len == 5)
+	return true;
+      if (delete_len == 6 && delete_name[5] == new_name[3])
+	return true;
+      if (delete_len == 19 && !memcmp (delete_name + 5, "RKSt9nothrow_t", 14))
+	return true;
+    }
+  else if ((new_len == 19 && !memcmp (new_name + 4, "St11align_val_t", 15))
+	   || (new_len == 33
+	       && !memcmp (new_name + 4, "St11align_val_tRKSt9nothrow_t", 29)))
+    {
+      /* _ZnXYSt11align_val_t or _ZnXYSt11align_val_tRKSt9nothrow_t matches
+	 _ZdXPvSt11align_val_t or _ZdXPvYSt11align_val_t or  or
+	 _ZdXPvSt11align_val_tRKSt9nothrow_t.  */
+      if (delete_len == 20 && !memcmp (delete_name + 5, "St11align_val_t", 15))
+	return true;
+      if (delete_len == 21
+	  && delete_name[5] == new_name[3]
+	  && !memcmp (delete_name + 6, "St11align_val_t", 15))
+	return true;
+      if (delete_len == 34
+	  && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29))
+	return true;
+    }
+  return false;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/tree.h b/gcc/tree.h
index 7faa49d42ba..24e1e19488b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5275,6 +5275,7 @@ extern tree tree_block (tree);
 extern void tree_set_block (tree, tree);
 extern location_t *block_nonartificial_location (tree);
 extern location_t tree_nonartificial_location (tree);
+extern location_t tree_inlined_location (tree, bool = true);
 extern tree block_ultimate_origin (const_tree);
 extern tree get_binfo_at_offset (tree, poly_int64, tree);
 extern bool virtual_method_call_p (const_tree, bool = false);
@@ -5352,6 +5353,7 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree,
 extern bool type_with_interoperable_signedness (const_tree);
 extern bitmap get_nonnull_args (const_tree);
 extern int get_range_pos_neg (tree);
+extern bool valid_new_delete_pair_p (tree, tree);
 
 /* Return simplified tree code of type that is used for canonical type
    merging.  */

[-- Attachment #3: gcc-98166-2.diff --]
[-- Type: text/x-patch, Size: 52702 bytes --]

Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160).

Resolves:
PR middle-end/98166 - bogus -Wmismatched-dealloc on user-defined allocator and inlining
PR c++/57111 - 57111 - Generalize -Wfree-nonheap-object to delete
PR middle-end/98160 - ICE in default_tree_printer at gcc/tree-diagnostic.c:270

gcc/ChangeLog:

	PR middle-end/98166
	PR c++/57111
	PR middle-end/98160
	* builtins.c (call_dealloc_p): Remove unused function.
	(new_delete_mismatch_p): Call valid_new_delete_pair_p and rework.
	(matching_alloc_calls_p): Handle built-in deallocation functions.
	(warn_dealloc_offset): Corrct the handling of user-defined operators
	delete.
	(maybe_emit_free_warning): Avoid assuming expression is a decl.
	Simplify.
	* doc/extend.texi (attribute malloc): Update.

gcc/c-family/ChangeLog:

	PR middle-end/98166
	PR c++/57111
	PR middle-end/98160
	* c-attribs.c (handle_malloc_attribute): Implicitly add attribute
	noinline to functions not declared inline and warn on those.

libstdc++-v3/ChangeLog:
	* testsuite/ext/vstring/requirements/exception/basic.cc: Suppress
	a false positive warning.
	* testsuite/ext/vstring/requirements/exception/propagation_consistent.cc:
	  Same.

gcc/testsuite/ChangeLog:

	PR middle-end/98166
	PR c++/57111
	PR middle-end/98160
	* g++.dg/warn/Wmismatched-dealloc-2.C: Adjust test of expected warning.
	* g++.dg/warn/Wmismatched-new-delete.C: Same.
	* gcc.dg/Wmismatched-dealloc.c: Same.
	* c-c++-common/Wfree-nonheap-object-2.c: New test.
	* c-c++-common/Wfree-nonheap-object-3.c: New test.
	* c-c++-common/Wfree-nonheap-object.c: New test.
	* c-c++-common/Wmismatched-dealloc.c: New test.
	* g++.dg/warn/Wfree-nonheap-object-3.C: New test.
	* g++.dg/warn/Wfree-nonheap-object-4.C: New test.
	* g++.dg/warn/Wmismatched-new-delete-2.C: New test.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index faa5030853b..434815b7410 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -13065,12 +13051,119 @@ call_dealloc_argno (tree exp)
   return UINT_MAX;
 }
 
-/* Return true if STMT is a call to a deallocation function.  */
+/* Return true if DELETE_DECL is an operator delete that's not suitable
+   to call with a pointer returned fron NEW_DECL.  */
 
-static inline bool
-call_dealloc_p (tree exp)
+static bool
+new_delete_mismatch_p (tree new_decl, tree delete_decl)
 {
-  return call_dealloc_argno (exp) != UINT_MAX;
+  tree new_name = DECL_ASSEMBLER_NAME (new_decl);
+  tree delete_name = DECL_ASSEMBLER_NAME (delete_decl);
+
+  /* valid_new_delete_pair_p() returns a conservative result.  A true
+     result is reliable but a false result doesn't necessarily mean
+     the operators don't match.  */
+  if (valid_new_delete_pair_p (new_name, delete_name))
+    return false;
+
+  const char *new_str = IDENTIFIER_POINTER (new_name);
+  const char *del_str = IDENTIFIER_POINTER (delete_name);
+
+  if (*new_str != '_')
+    return *new_str != *del_str;
+
+  ++del_str;
+  if (*++new_str != 'Z')
+    return *new_str != *del_str;
+
+  ++del_str;
+  if (*++new_str == 'n')
+    return *del_str != 'd';
+
+  if (*new_str != 'N')
+    return *del_str != 'N';
+
+  /* Handle user-defined member operators below.  */
+  ++new_str;
+  ++del_str;
+
+  do
+    {
+      /* Determine if both operators are members of the same type.
+	 If not, they don't match.  */
+      char *new_end, *del_end;
+      unsigned long nlen = strtoul (new_str, &new_end, 10);
+      unsigned long dlen = strtoul (del_str, &del_end, 10);
+      if (nlen != dlen)
+	return true;
+
+      /* Skip past the name length.   */
+      new_str = new_end;
+      del_str = del_end;
+
+      /* Skip past the names making sure each has the expected length
+	 (it would suggest some sort of a corruption if they didn't).  */
+      while (nlen--)
+	if (!*++new_end)
+	  return true;
+
+      for (nlen = dlen; nlen--; )
+	if (!*++del_end)
+	  return true;
+
+      /* The names have the expected length.  Compare them.  */
+      if (memcmp (new_str, del_str, dlen))
+	return true;
+
+      new_str = new_end;
+      del_str = del_end;
+
+      if (*new_str == 'I')
+	{
+	  /* Template instantiation.  */
+	  do
+	    {
+	      ++new_str;
+	      ++del_str;
+
+	      if (*new_str == 'n')
+		break;
+	      if (*new_str != *del_str)
+		return true;
+	    }
+	  while (*new_str);
+	}
+
+      if (*new_str == 'n')
+	{
+	  if (*del_str != 'd')
+	    return true;
+
+	  ++del_str;
+	  if (*++new_str == 'w' && *del_str != 'l')
+	    return true;
+	  if (*new_str == 'a' && *del_str != 'a')
+	    return true;
+	  ++new_str;
+	  ++del_str;
+	  break;
+	}
+    } while (true);
+
+  if (*new_str != 'E')
+    return *del_str != *new_str;
+
+  ++new_str;
+  ++del_str;
+  if (*new_str != 'j' && *new_str != 'm' && *new_str != 'y')
+    return true;
+  if (*del_str != 'P' || *++del_str != 'v')
+    return true;
+
+  /* Ignore any remaining arguments.  Since both operators are members
+     of the same class, mismatches in those should be detectable and
+     diagnosed by the front end.  */
+  return false;
 }
 
 /* ALLOC_DECL and DEALLOC_DECL are pair of allocation and deallocation
@@ -13083,15 +13176,9 @@ matching_alloc_calls_p (tree alloc_decl, tree dealloc_decl)
   if (DECL_IS_OPERATOR_NEW_P (alloc_decl))
     {
       if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl))
-	{
-	  /* Return true iff both functions are of the same array or
-	     singleton form and false otherwise.  */
-	  tree alloc_id = DECL_NAME (alloc_decl);
-	  tree dealloc_id = DECL_NAME (dealloc_decl);
-	  const char *alloc_fname = IDENTIFIER_POINTER (alloc_id);
-	  const char *dealloc_fname = IDENTIFIER_POINTER (dealloc_id);
-	  return !strchr (alloc_fname, '[') == !strchr (dealloc_fname, '[');
-	}
+	/* Return true iff both functions are of the same array or
+	   singleton form and false otherwise.  */
+	return !new_delete_mismatch_p (alloc_decl, dealloc_decl);
 
       /* Return false for deallocation functions that are known not
 	 to match.  */
@@ -13128,13 +13215,35 @@ matching_alloc_calls_p (tree alloc_decl, tree dealloc_decl)
 	}
     }
 
-  /* If DEALLOC_DECL has internal "*dealloc" attribute scan the list of
-     its associated allocation functions for ALLOC_DECL.  If it's found
-     they are a matching pair, otherwise they're not.  */
-  tree attrs = DECL_ATTRIBUTES (dealloc_decl);
-  if (!attrs)
-    return false;
+  if (fndecl_built_in_p (dealloc_decl, BUILT_IN_NORMAL))
+    {
+      tree alloc_attrs = DECL_ATTRIBUTES (alloc_decl);
+      built_in_function dealloc_code = DECL_FUNCTION_CODE (dealloc_decl);
+
+      for (tree alloc_funs = alloc_attrs;
+	   (alloc_funs = lookup_attribute ("malloc", alloc_funs));
+	   alloc_funs = TREE_CHAIN (alloc_funs))
+	{
+	  tree args = TREE_VALUE (alloc_funs);
+	  if (!args)
+	    continue;
+
+	  tree fndecl = TREE_VALUE (args);
+	  if (fndecl
+	      && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+	      && dealloc_code == DECL_FUNCTION_CODE (fndecl))
+	    return true;
+	}
+      return false;
+    }
 
+  /* If DEALLOC_DECL has an internal "*dealloc" attribute scan the list
+     of its associated allocation functions for ALLOC_DECL.  In addition,
+     for built-ins, search the list of attributes of both the form
+     referenced by the attribute and the "internal" __builtin_xxx form/
+     If the corresponding ALLOC_DECL is found they're a matching pair,
+     otherwise they're not.  */
+  tree attrs = DECL_ATTRIBUTES (dealloc_decl);
   for (tree funs = attrs;
        (funs = lookup_attribute ("*dealloc", funs));
        funs = TREE_CHAIN (funs))
@@ -13167,15 +13276,36 @@ matching_alloc_calls_p (gimple *alloc, tree dealloc_decl)
   return matching_alloc_calls_p (alloc_decl, dealloc_decl);
 }
 
-/* Diagnose a call to FNDECL to deallocate a pointer referenced by
-   AREF that includes a nonzero offset.  Such a pointer cannot refer
-   to the beginning of an allocated object.  A negative offset may
-   refer to it only if the target pointer is unknown.  */
+/* Diagnose a call EXP to deallocate a pointer referenced by AREF if it
+   includes a nonzero offset.  Such a pointer cannot refer to the beginning
+   of an allocated object.  A negative offset may refer to it only if
+   the target pointer is unknown.  */
 
 static bool
-warn_dealloc_offset (location_t loc, tree exp, tree fndecl,
-		     const access_ref &aref)
+warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref)
 {
+  if (aref.deref || aref.offrng[0] <= 0 || aref.offrng[1] <= 0)
+    return false;
+
+  tree dealloc_decl = get_callee_fndecl (exp);
+  if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl)
+      && !DECL_IS_REPLACEABLE_OPERATOR (dealloc_decl))
+    {
+      /* A call to a user-defined operator delete with a pointer plus offset
+	 may be valid if it's returned from an unknown function (i.e., one
+	 that's not operator new).  */
+      if (TREE_CODE (aref.ref) == SSA_NAME)
+	{
+	  gimple *def_stmt = SSA_NAME_DEF_STMT (aref.ref);
+	  if (is_gimple_call (def_stmt))
+	    {
+	      tree alloc_decl = gimple_call_fndecl (def_stmt);
+	      if (!DECL_IS_OPERATOR_NEW_P (alloc_decl))
+		return false;
+	    }
+	}
+    }
+
   char offstr[80];
   offstr[0] = '\0';
   if (wi::fits_shwi_p (aref.offrng[0]))
@@ -13192,7 +13322,7 @@ warn_dealloc_offset (location_t loc, tree exp, tree fndecl,
 
   if (!warning_at (loc, OPT_Wfree_nonheap_object,
 		   "%K%qD called on pointer %qE with nonzero offset%s",
-		   exp, fndecl, aref.ref, offstr))
+		   exp, dealloc_decl, aref.ref, offstr))
     return false;
 
   if (DECL_P (aref.ref))
@@ -13202,9 +13332,16 @@ warn_dealloc_offset (location_t loc, tree exp, tree fndecl,
       gimple *def_stmt = SSA_NAME_DEF_STMT (aref.ref);
       if (is_gimple_call (def_stmt))
 	{
+	  location_t def_loc = gimple_location (def_stmt);
 	  tree alloc_decl = gimple_call_fndecl (def_stmt);
-	  inform (gimple_location (def_stmt),
-		  "returned from a call to %qD", alloc_decl);
+	  if (alloc_decl)
+	    inform (def_loc,
+		    "returned from %qD", alloc_decl);
+	  else if (tree alloc_fntype = gimple_call_fntype (def_stmt))
+	    inform (def_loc,
+		    "returned from %qT", alloc_fntype);
+	  else
+	    inform (def_loc,  "obtained here");
 	}
     }
 
@@ -13240,8 +13377,7 @@ maybe_emit_free_warning (tree exp)
     return;
 
   tree dealloc_decl = get_callee_fndecl (exp);
-  location_t loc = tree_nonartificial_location (exp);
-  loc = expansion_point_location_if_in_system_header (loc);
+  location_t loc = tree_inlined_location (exp);
 
   if (DECL_P (ref) || EXPR_P (ref))
     {
@@ -13251,18 +13387,18 @@ maybe_emit_free_warning (tree exp)
 			 "%K%qD called on unallocated object %qD",
 			 exp, dealloc_decl, ref))
 	{
-	  inform (DECL_SOURCE_LOCATION (ref),
-		  "declared here");
+	  loc = (DECL_P (ref)
+		 ? DECL_SOURCE_LOCATION (ref)
+		 : EXPR_LOCATION (ref));
+	  inform (loc, "declared here");
 	  return;
 	}
 
       /* Diagnose freeing a pointer that includes a positive offset.
 	 Such a pointer cannot refer to the beginning of an allocated
 	 object.  A negative offset may refer to it.  */
-      if (!aref.deref
-	  && aref.sizrng[0] != aref.sizrng[1]
-	  && aref.offrng[0] > 0 && aref.offrng[1] > 0
-	  && warn_dealloc_offset (loc, exp, dealloc_decl, aref))
+      if (aref.sizrng[0] != aref.sizrng[1]
+	  && warn_dealloc_offset (loc, exp, aref))
 	return;
     }
   else if (CONSTANT_CLASS_P (ref))
@@ -13295,9 +13431,7 @@ maybe_emit_free_warning (tree exp)
 	    {
 	      if (matching_alloc_calls_p (def_stmt, dealloc_decl))
 		{
-		  if (!aref.deref
-		      && aref.offrng[0] > 0 && aref.offrng[1] > 0
-		      && warn_dealloc_offset (loc, exp, dealloc_decl, aref))
+		  if (warn_dealloc_offset (loc, exp, aref))
 		    return;
 		}
 	      else
@@ -13320,16 +13454,14 @@ maybe_emit_free_warning (tree exp)
 				 "%K%qD called on pointer to "
 				 "an unallocated object",
 				 exp, dealloc_decl);
-	  else if (!aref.deref
-		   && aref.offrng[0] > 0 && aref.offrng[1] > 0
-		   && warn_dealloc_offset (loc, exp, dealloc_decl, aref))
+	  else if (warn_dealloc_offset (loc, exp, aref))
 	    return;
 
 	  if (warned)
 	    {
 	      tree fndecl = gimple_call_fndecl (def_stmt);
 	      inform (gimple_location (def_stmt),
-		      "returned from a call to %qD", fndecl);
+		      "returned from %qD", fndecl);
 	      return;
 	    }
 	}
@@ -13341,7 +13473,7 @@ maybe_emit_free_warning (tree exp)
 	      && !aref.deref
 	      && aref.sizrng[0] != aref.sizrng[1]
 	      && aref.offrng[0] > 0 && aref.offrng[1] > 0
-	      && warn_dealloc_offset (loc, exp, dealloc_decl, aref))
+	      && warn_dealloc_offset (loc, exp, aref))
 	    return;
 	}
     }
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index f7dad7a91d7..7974a7088f9 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -3174,11 +3174,21 @@ handle_malloc_attribute (tree *node, tree name, tree args,
       return NULL_TREE;
     }
 
-  /* In C++ the argument may be wrapped in a cast to disambiguate one
-     of a number of overloads (such as operator delete).  Strip it.  */
   STRIP_NOPS (dealloc);
   if (TREE_CODE (dealloc) == ADDR_EXPR)
-    dealloc = TREE_OPERAND (dealloc, 0);
+    {
+      /* In C++ the argument may be wrapped in a cast to disambiguate
+	 one of a number of overloads (such as operator delete).  To
+	 make things interesting, the cast looks different between
+	 different C++ versions.  Strip it and install the attribute
+	 with the disambiguated function.  */
+      dealloc = TREE_OPERAND (dealloc, 0);
+
+      *no_add_attrs = true;
+      tree attr = tree_cons (NULL_TREE, dealloc, TREE_CHAIN (args));
+      attr = build_tree_list (name, attr);
+      return decl_attributes (node, attr, 0);
+    }
 
   if (TREE_CODE (dealloc) != FUNCTION_DECL)
     {
@@ -3234,9 +3244,50 @@ handle_malloc_attribute (tree *node, tree name, tree args,
 	}
 
       *no_add_attrs = false;
-      tree attr_free = build_tree_list (NULL_TREE, DECL_NAME (fndecl));
-      attr_free = build_tree_list (get_identifier ("*dealloc"), attr_free);
-      decl_attributes (&dealloc, attr_free, 0);
+
+      tree at_noinline = NULL_TREE;
+      if (!fndecl_built_in_p (fndecl) && !fndecl_built_in_p (dealloc))
+	{
+	  /* When inlining (or optimization) is enabled and the allocator
+	     and deallocator are not built-in functions, ignore
+	     the attribute on functions declared inline since it could
+	     lead to false positives when inlining one or the other
+	     call would wind up calling a mismatched allocator or
+	     deallocator.  */
+	  if ((optimize && DECL_DECLARED_INLINE_P (fndecl))
+	      || lookup_attribute ("always_inline", DECL_ATTRIBUTES (fndecl)))
+	    {
+	      warning (OPT_Wattributes,
+		       "%<%E (%E)%> attribute ignored on functions "
+		       "declared %qs", name, DECL_NAME (dealloc), "inline");
+	      *no_add_attrs = true;
+	      return NULL_TREE;
+	    }
+
+	  if ((optimize && DECL_DECLARED_INLINE_P (dealloc))
+	      || lookup_attribute ("always_inline", DECL_ATTRIBUTES (dealloc)))
+	    {
+	      warning (OPT_Wattributes,
+		       "%<%E (%E)%> attribute ignored with deallocation "
+		       "functions declared %qs",
+		       name, DECL_NAME (dealloc), "inline");
+	      inform (DECL_SOURCE_LOCATION (dealloc),
+		      "deallocation function declared here" );
+	      *no_add_attrs = true;
+	      return NULL_TREE;
+	    }
+
+	  /* Disable inlining for non-standard deallocators to avoid false
+	     positives due to mismatches between the inlined implementation
+	     of one and not the other pair of functions.  */
+	  at_noinline
+	    = tree_cons (get_identifier ("noinline"), NULL_TREE, NULL_TREE);
+	  decl_attributes (&fndecl, at_noinline, 0);
+	}
+
+      tree attrs = build_tree_list (NULL_TREE, DECL_NAME (fndecl));
+      attrs = tree_cons (get_identifier ("*dealloc"), attrs, at_noinline);
+      decl_attributes (&dealloc, attrs, 0);
       return NULL_TREE;
     }
 
diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
new file mode 100644
index 00000000000..0aedf1babbc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
@@ -0,0 +1,52 @@
+/* PR middle-end/98166: bogus -Wmismatched-dealloc on user-defined allocator
+   and inlining
+   Verify that the allocator can be declared inline without a warning when
+   it's associated with a standard deallocator.  Associating an inline
+   deallocator with an allocator would cause false positives when the former
+   calls a deallocation function the allocator isn't associated with, so
+   that triggers a warning on declaration.
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+__attribute__ ((malloc (__builtin_free)))
+inline int*
+alloc_int (int n)
+{
+  return (int*)__builtin_malloc (n + sizeof (int));
+}
+
+void test_nowarn_int (int n)
+{
+  {
+    int *p = alloc_int (n);
+    __builtin_free (p);
+  }
+
+  {
+    int *p = alloc_int (n);
+    __builtin_free (p + 1);   // { dg-warning "\\\[-Wfree-nonheap-object" }
+  }
+}
+
+
+inline void
+dealloc_long (long *p)
+{
+  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+}
+
+__attribute__ ((malloc (dealloc_long)))
+long* alloc_long (int);       // { dg-warning "'malloc \\\(dealloc_long\\\)' attribute ignored with deallocation functions declared 'inline'" }
+
+void test_nowarn_long (int n)
+{
+  {
+    long *p = alloc_long (n);
+    dealloc_long (p);
+  }
+
+  {
+    long *p = alloc_long (n);
+    dealloc_long (p + 1);
+  }
+}
diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
new file mode 100644
index 00000000000..41a5b50362e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
@@ -0,0 +1,70 @@
+/* PR middle-end/98166: bogus -Wmismatched-dealloc on user-defined allocator
+   and inlining
+   Verify that without inlining, both the allocator and the deallocator
+   can be declared inline without a warning and that mismatched calls are
+   detected, but that declaring them always_inline does trigger a warning.
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+__attribute__ ((malloc (__builtin_free)))
+inline int*
+alloc_int (int n)
+{
+  return (int*)__builtin_malloc (n + sizeof (int));
+}
+
+void test_nowarn_int (int n)
+{
+  {
+    int *p = alloc_int (n);
+    __builtin_free (p);
+  }
+
+  {
+    int *p = alloc_int (n);
+    __builtin_free (p + 1);   // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  }
+}
+
+
+inline void
+dealloc_long (long *p) { __builtin_free (p); }
+
+__attribute__ ((malloc (dealloc_long)))
+long* alloc_long (int);
+
+void test_nowarn_long (int n)
+{
+  {
+    long *p = alloc_long (n);
+    dealloc_long (p);
+  }
+
+  {
+    long *p = alloc_long (n);
+    dealloc_long (p + 1);     // { dg-warning "'dealloc_long' called on pointer 'p|<unknown>' with nonzero offset" }
+  }
+}
+
+
+inline __attribute__ ((always_inline)) void
+dealloc_float (float *p)      // { dg-message "deallocation function declared here" }
+{
+  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+}
+
+__attribute__ ((malloc (dealloc_float)))
+float* alloc_float (int);     // { dg-warning "'malloc \\(dealloc_float\\)' attribute ignored with deallocation functions declared 'inline'" }
+
+void test_nowarn_float (int n)
+{
+  {
+    float *p = alloc_float (n);
+    dealloc_float (p);
+  }
+
+  {
+    float *p = alloc_float (n);
+    dealloc_float (p + 2);
+  }
+}
diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
new file mode 100644
index 00000000000..dfbb296e9a7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
@@ -0,0 +1,50 @@
+/* Verify that built-in forms of functions can be used interchangeably
+   with their ordinary (library) forms in attribute malloc.
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+char* f (void) __attribute__ ((malloc (__builtin_free)));
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void free (void*);
+
+#if __cplusplus
+}
+#endif
+
+char* g (void) __attribute__ ((malloc (free)));
+
+
+void test_nowarm (void)
+{
+  char *p = f ();
+  free (p);
+
+  p = g ();
+  free (p);
+
+  p = f ();
+  __builtin_free (p);
+
+  p = g ();
+  __builtin_free (p);
+}
+
+
+void test_warn (void)
+{
+  char *p = f ();
+  free (p + 1);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+
+  p = g ();
+  free (p + 2);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+
+  p = f ();
+  __builtin_free (p + 3);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+
+  p = g ();
+  __builtin_free (p + 4);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+}
diff --git a/gcc/testsuite/c-c++-common/Wmismatched-dealloc.c b/gcc/testsuite/c-c++-common/Wmismatched-dealloc.c
new file mode 100644
index 00000000000..9315f74973c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wmismatched-dealloc.c
@@ -0,0 +1,67 @@
+/* PR middle-end/98166: bogus -Wmismatched-dealloc on user-defined allocator
+   and inlining
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+
+void dealloc_shrt (short *p)
+{
+  /* A positive offset would be diagnosed but a negative one must
+     not be.  */
+  __builtin_free (p - 1);     // { dg-bogus "-Wmismatched-dealloc" }
+}
+
+__attribute__ ((malloc (dealloc_shrt)))
+short* alloc_shrt (int n) /* { return malloc (n) + 1; } */;
+
+void test_nowarn_shrt (int n)
+{
+  short *p = alloc_shrt (n);
+  dealloc_shrt (p);
+}
+
+
+void dealloc_int (int *p) /* { free (p - 1); } */;
+
+__attribute__ ((malloc (dealloc_int)))
+int* alloc_int (int n)
+{
+  return (int*)__builtin_malloc (n) + 1;
+}
+
+void test_nowarn_int (int n)
+{
+  int *p = alloc_int (n);
+  dealloc_int (p);          // { dg-bogus "-Wmismatched-dealloc" }
+}
+
+
+void dealloc_long (long *p) /* { free (p - 2); } */;
+
+__attribute__ ((malloc (dealloc_long)))
+inline long*
+alloc_long (int n) {          // { dg-warning "'malloc \\(\[^\n\r\]*dealloc_long\[^\n\r\]*\\)' attribute ignored on functions declared 'inline'" }
+  return (long*)__builtin_malloc (n) + 2;
+}
+
+void test_nowarn_long (int n)
+{
+  long *p = alloc_long (n);
+  dealloc_long (p);           // { dg-bogus "\\\[-Wmismatched-dealloc" }
+}
+
+
+inline void
+dealloc_float (float *p)      // { dg-message "deallocation function declared here" }
+{
+  __builtin_free (p - 3);
+}
+
+__attribute__ ((malloc (dealloc_float)))
+float* alloc_float (int n);   // { dg-warning "'malloc \\(\[^\n\r\]*dealloc_float\[^\n\r\]*\\)' attribute ignored with deallocation functions declared 'inline'" }
+
+void test_nowarn_float (int n)
+{
+  float *p = alloc_float (n);
+  dealloc_float (p);          // { dg-bogus "\\\[-Wmismatched-dealloc" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-3.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-3.C
new file mode 100644
index 00000000000..47f97dcb636
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-3.C
@@ -0,0 +1,38 @@
+/* PR c++/57111 - Generalize -Wfree-nonheap-object to delete
+   Verify that even without -Wsystem-headers the warning is issued
+   for pairs of library functions defined in system headers.
+   { dg-do compile { target c++11 } }
+   { dg-options "-O2 -Wall" } */
+
+#include <memory>
+#include <string>
+
+void test_string ()
+{
+  std::string str ("abc");          // { dg-message "declared here" }
+
+  const char *s = str.c_str ();
+  __builtin_printf ("%s\n", s);
+
+  /* Because the delete call is made directly in the function this
+     does not exercise the same thing as test_unique_ptr.  */
+  delete s;                         // { dg-warning "'void operator delete\\(void\\*\[^\\)\]*\\)' called on unallocated object 'str'" }
+}
+
+void test_unique_ptr ()
+{
+  int arr[]= { 1, 2 };              // { dg-message "declared here" }
+
+  std::unique_ptr<int[]> up (arr);
+  __builtin_printf ("%i %i\n", up[0], up[1]);
+
+  /* TO DO: verify that the warning is printed, including its inlining
+     context (the directive below doesn't work):
+     { Xdg-message "In member function.*inlined from 'void test_unique_ptr\\(\\)'.*warning: 'void operator delete \\\[]\\(void\\*\\)' called on unallocated object 'arr'" "" { target *-*-* } 0 }  */
+
+  /* Here, the delete call is made indirectly from std::unique_ptr
+     dtor.  */
+}
+
+/* Prune out the warning from test_unique_ptr().
+   { dg-prune-output "-Wfree-nonheap-object" } */
diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-4.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-4.C
new file mode 100644
index 00000000000..943ef0cd1ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-4.C
@@ -0,0 +1,26 @@
+/* PR middle-end/98160: bogus -Wfree-nonheap-object calling member delete
+   on the result of inline member new plus offset
+   { dg-do compile }
+   { dg-options "-O2" } */
+
+struct MemoryManager { void* allocate (); };
+
+struct XMemory
+{
+  void* operator new (__SIZE_TYPE__, MemoryManager *mgr)
+  {
+    void *p = mgr->allocate ();
+    return (char*)p + sizeof(MemoryManager);
+  }
+
+  void operator delete (void*, MemoryManager*);
+};
+
+struct XMLMutex: XMemory {
+  XMLMutex();
+};
+
+void gValidatorMutex (MemoryManager *mgr)
+{
+  new (mgr) XMLMutex;   // { dg-bogus "\\\[-Wfree-nonheap-object" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
index 7ecc99a325c..3aea02fa63d 100644
--- a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
@@ -59,13 +59,13 @@ void test_my_new ()
 
   {
     void *p = my_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     operator delete[] (p);
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 }
   }
   {
     void *p = my_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     operator delete[] (p);
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 }
@@ -89,7 +89,7 @@ void test_my_new ()
 
   {
     void *p = my_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     my_array_delete ("3", p);
     // { dg-warning "'void my_array_delete\\\(const char\\\*, void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -97,7 +97,7 @@ void test_my_new ()
 
   {
     void *p = my_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     free (p);
     // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -105,7 +105,7 @@ void test_my_new ()
 
   {
     void *p = my_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     p = realloc (p, 123);
     // { dg-warning "'void\\\* realloc\\\(void\\\*, size_t\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -132,13 +132,13 @@ void test_my_array_new ()
 
   {
     void *p = my_array_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     operator delete (p);
     // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 }
   }
   {
     void *p = my_array_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     operator delete (p);
     // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function \\\[-Wmismatched-new-delete" "" { target *-*-* } .-1 }
@@ -161,7 +161,7 @@ void test_my_array_new ()
   }
   {
     void *p = my_array_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     my_delete ("3", p);
     // { dg-warning "'void my_delete\\\(const char\\\*, void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -169,7 +169,7 @@ void test_my_array_new ()
 
   {
     void *p = my_array_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     free (p);
     // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -177,7 +177,7 @@ void test_my_array_new ()
 
   {
     void *p = my_array_new (1);
-    // { dg-message "returned from a call to 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'int\\\* my_array_new\\\(size_t\\\)'" "note" { target *-*-* } .-1 }
     sink (p);
     p = realloc (p, 123);
     // { dg-warning "'void\\\* realloc\\\(void\\\*, size_t\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
index ed1090be5c5..fc07149995d 100644
--- a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
@@ -44,14 +44,14 @@ void warn_new_free (int n)
 {
   {
     void *p = operator new (n);
-    // { dg-message "returned from a call to 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 }
     sink (p);
     free (p);
     // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
   }
   {
     char *p = new char[n];
-    // { dg-message "returned from a call to 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 }
     sink (p);
     free (p);
     // { dg-warning "'void free\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -66,7 +66,7 @@ void warn_new_realloc (int n)
 {
   {
     void *p = operator new (n);
-    // { dg-message "returned from a call to 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* operator new\\\(" "note" { target *-*-* } .-1 }
     sink (p);
     p = realloc (p, n * 2);
     // { dg-warning "'void\\\* realloc\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -74,7 +74,7 @@ void warn_new_realloc (int n)
   }
   {
     void *p = new char[n];
-    // { dg-message "returned from a call to 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* operator new \\\[" "note" { target *-*-* } .-1 }
     sink (p);
     p = realloc (p, n * 2);
     // { dg-warning "'void\\\* realloc\\\(\[^)\]+\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -89,7 +89,7 @@ void warn_new_realloc (int n)
 void warn_malloc_op_delete (int n)
 {
   char *p = (char *)malloc (n);
-  // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
+  // { dg-message "returned from 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
   sink (p);
   operator delete (p);
   // { dg-warning "'void operator delete\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -97,13 +97,13 @@ void warn_malloc_op_delete (int n)
 
 
 /* Verify a warning for an invocation of either form of the delete
-   expression with a pointer returned from a call to malloc().  */
+   expression with a pointer returned from malloc().  */
 
 void warn_malloc_delete (int n)
 {
   {
     char *p = (char *)malloc (n);
-    // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
     sink (p);
     /* C++98 calls operator delete (void*) but later versions call
        operator delete (void*, size_t).  The difference doesn't matter
@@ -114,7 +114,7 @@ void warn_malloc_delete (int n)
 
   {
     char *p = (char *)malloc (n);
-    // { dg-message "returned from a call to 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* malloc\\\(" "note" { target *-*-* } .-1 }
     sink (p);
     delete[] p;
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -123,13 +123,13 @@ void warn_malloc_delete (int n)
 
 
 /* Verify a warning for an invocation of either form of the delete
-   expression with a pointer returned from a call to realloc().  */
+   expression with a pointer returned from realloc().  */
 
 void warn_realloc_delete (void *p1, void *p2, int n)
 {
   {
     char *q = (char *)realloc (p1, n);
-    // { dg-message "returned from a call to 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     /* C++98 calls operator delete (void*) but later versions call
        operator delete (void*, size_t).  The difference doesn't matter
@@ -140,7 +140,7 @@ void warn_realloc_delete (void *p1, void *p2, int n)
 
   {
     char *q = (char *)realloc (p2, n);
-    // { dg-message "returned from a call to 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'void\\\* realloc\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     delete[] q;
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -149,13 +149,13 @@ void warn_realloc_delete (void *p1, void *p2, int n)
 
 
 /* Verify a warning for an invocation of either form of the delete
-   expression with a pointer returned from a call to strdup().  */
+   expression with a pointer returned from strdup().  */
 
 void warn_strdup_delete (const char *s1, const char *s2)
 {
   {
     char *q = strdup (s1);
-    // { dg-message "returned from a call to 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     /* C++98 calls operator delete (void*) but later versions call
        operator delete (void*, size_t).  The difference doesn't matter
@@ -166,7 +166,7 @@ void warn_strdup_delete (const char *s1, const char *s2)
 
   {
     char *q = strdup (s2);
-    // { dg-message "returned from a call to 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'char\\\* strdup\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     delete[] q;
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
@@ -176,13 +176,13 @@ void warn_strdup_delete (const char *s1, const char *s2)
 
 
 /* Verify a warning for an invocation of either form of the delete
-   expression with a pointer returned from a call to strndup().  */
+   expression with a pointer returned from strndup().  */
 
 void warn_strdup_delete (const char *s1, const char *s2, size_t n)
 {
   {
     char *q = strndup (s1, n);
-    // { dg-message "returned from a call to 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     /* C++98 calls operator delete (void*) but later versions call
        operator delete (void*, size_t).  The difference doesn't matter
@@ -193,7 +193,7 @@ void warn_strdup_delete (const char *s1, const char *s2, size_t n)
 
   {
     char *q = strndup (s2, n);
-    // { dg-message "returned from a call to 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 }
+    // { dg-message "returned from 'char\\\* strndup\\\(" "note" { target *-*-* } .-1 }
     sink (q);
     delete[] q;
     // { dg-warning "'void operator delete \\\[]\\\(void\\\*\\\)' called on pointer returned from a mismatched allocation function" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c b/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c
index 7c5d6acf4d6..38fd44ebdc8 100644
--- a/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c
+++ b/gcc/testsuite/gcc.dg/Wmismatched-dealloc.c
@@ -68,18 +68,18 @@ void nowarn_fdopen (void)
 void warn_fdopen (void)
 {
   {
-    FILE *q = fdopen (0);     // { dg-message "returned from a call to 'fdopen'" "note" }
+    FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
     sink (q);
     release (q);              // { dg-warning "'release' called on pointer returned from a mismatched allocation function" }
   }
   {
-    FILE *q = fdopen (0);     // { dg-message "returned from a call to 'fdopen'" "note" }
+    FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
     sink (q);
     free (q);                 // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *q = fdopen (0);     // { dg-message "returned from a call to 'fdopen'" "note" }
+    FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
     sink (q);
     q = realloc (q, 7);       // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
     sink (q);
@@ -142,7 +142,7 @@ void test_popen (void)
 
   {
     FILE *p;
-    p = popen ("2", "r");     // { dg-message "returned from a call to 'popen'" "note" }
+    p = popen ("2", "r");     // { dg-message "returned from 'popen'" "note" }
     sink (p);
     fclose (p);               // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" }
   }
@@ -152,7 +152,7 @@ void test_popen (void)
        close the stream returned from freopen().  */
     FILE *p = popen ("2", "r");
     sink (p);
-    p = freopen ("3", "r", p);  // { dg-message "returned from a call to 'freopen'" "note" }
+    p = freopen ("3", "r", p);  // { dg-message "returned from 'freopen'" "note" }
     sink (p);
     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
   }
@@ -176,7 +176,7 @@ void test_tmpfile (void)
   }
 
   {
-    FILE *p = tmpfile ();     // { dg-message "returned from a call to 'tmpfile'" "note" }
+    FILE *p = tmpfile ();     // { dg-message "returned from 'tmpfile'" "note" }
     sink (p);
     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
   }
@@ -186,19 +186,19 @@ void test_tmpfile (void)
 void warn_malloc (void)
 {
   {
-    FILE *p = malloc (100);   // { dg-message "returned from a call to 'malloc'" "note" }
+    FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
     sink (p);
     fclose (p);               // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *p = malloc (100);   // { dg-message "returned from a call to 'malloc'" "note" }
+    FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
     sink (p);
     p = freopen ("1", "r", p);// { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *p = malloc (100);   // { dg-message "returned from a call to 'malloc'" "note" }
+    FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
     sink (p);
     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
   }
@@ -219,32 +219,32 @@ void test_acquire (void)
   }
 
   {
-    FILE *p = acquire ();     // { dg-message "returned from a call to 'acquire'" "note" }
+    FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
     sink (p);
     fclose (p);               // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *p = acquire ();     // { dg-message "returned from a call to 'acquire'" "note" }
+    FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
     sink (p);
     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *p = acquire ();     // { dg-message "returned from a call to 'acquire'" "note" }
+    FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
     sink (p);
     p = freopen ("1", "r", p);  // { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" }
     sink (p);
   }
 
   {
-    FILE *p = acquire ();     // { dg-message "returned from a call to 'acquire'" "note" }
+    FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
     sink (p);
     free (p);               // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
   }
 
   {
-    FILE *p = acquire ();     // { dg-message "returned from a call to 'acquire'" "note" }
+    FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
     sink (p);
     p = realloc (p, 123);     // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
     sink (p);
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0c969085d1f..e88beb66dbb 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -3262,7 +3262,11 @@ under the control of options such as @option{-Wmismatched-dealloc}.
 To indicate that an allocation function both satisifies the nonaliasing
 property and has a deallocator associated with it, both the plain form
 of the attribute and the one with the @var{deallocator} argument must
-be used.
+be used.  Since inlining one of a the associated functions but not
+the other could result in apparent mismatches, this form of attribute
+@code{malloc} is not accepted on inline functions declared.  For
+the same reason, using the attribute prevents both the allocation
+and deallocation functions from being expanded inline.
 
 For example, besides stating that the functions return pointers that do
 not alias any others, the following declarations make the @code{fclose}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-2.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-2.C
new file mode 100644
index 00000000000..d0d53b38b93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-2.C
@@ -0,0 +1,249 @@
+/* Verify that implicit and explicit calls to member operator new and delete
+   are handled correctly.
+   { dg-do compile }
+   { dg-options "-Wmismatched-new-delete" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+namespace std
+{
+#if __cplusplus >= 201703L
+enum class align_val_t: size_t { };
+#else
+enum align_val_t { };
+#endif
+
+struct nothrow_t { };
+const nothrow_t nothrow = { };
+}
+
+void sink (void*, ...);
+
+struct POD
+{
+  void* operator new (size_t);
+  void operator delete (void*);
+
+  void* operator new[] (size_t);
+  void operator delete[] (void*);
+};
+
+POD* nowarn_pod ()
+{
+  POD *p = new POD;
+  delete p;
+  return new POD;
+}
+
+void warn_pod_array_mismatch ()
+{
+  POD *p = new POD;
+  delete[] p;                 // { dg-warning "'static void POD::operator delete \\\[]\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+  p = new POD[3];
+  delete p;                   // { dg-warning "'static void POD::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+}
+
+
+struct X1
+{
+  X1 ();
+
+  void* operator new (size_t);
+  void* operator new (size_t, std::align_val_t);
+  void* operator new (size_t, std::nothrow_t) throw ();
+  void* operator new (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+  void* operator new[] (size_t);
+  void* operator new[] (size_t, std::align_val_t);
+  void* operator new[] (size_t, std::nothrow_t) throw ();
+  void* operator new[] (size_t, std::align_val_t, std::nothrow_t) throw ();
+
+  void operator delete (void*);
+  void operator delete (void*, size_t);
+  void operator delete (void*, std::align_val_t);
+  void operator delete (void*, size_t, std::align_val_t);
+  void operator delete (void*, std::nothrow_t) throw ();
+  void operator delete (void*, std::align_val_t, std::nothrow_t) throw ();
+
+  void operator delete[] (void*);
+  void operator delete[] (void*, size_t);
+  void operator delete[] (void*, std::align_val_t);
+  void operator delete[] (void*, size_t, std::align_val_t);
+  void operator delete[] (void*, std::nothrow_t) throw ();
+  void operator delete[] (void*, std::align_val_t, std::nothrow_t) throw ();
+};
+
+X1* nowarn_x1 ()
+{
+  return new X1;
+}
+
+X1* nowarn_x1_array ()
+{
+  return new X1[2];
+}
+
+X1* nowarn_align_val ()
+{
+  X1 *p = new (std::align_val_t (32)) X1;
+  delete p;
+  return new (std::align_val_t (64)) X1;
+}
+
+X1* nowarn_align_val_array ()
+{
+  X1 *p = new (std::align_val_t (32)) X1[2];
+  delete[] p;
+  return new (std::align_val_t (64)) X1[2];
+}
+
+X1* nowarn_x1_nothrow ()
+{
+  X1 *p = new (std::nothrow) X1;
+  delete p;
+  return new (std::nothrow) X1;
+}
+
+X1* nowarn_x1_nothrow_array ()
+{
+  X1 *p = new (std::nothrow) X1[3];
+  delete[] p;
+  return new (std::nothrow) X1[3];
+}
+
+X1* nowarn_align_val_nothrow ()
+{
+  X1 *p = new (std::align_val_t (32), std::nothrow) X1;
+  delete p;
+  return new (std::align_val_t (64), std::nothrow) X1;
+}
+
+X1* nowarn_align_val_nothrow_array ()
+{
+  X1 *p = new (std::align_val_t (32), std::nothrow) X1[4];
+  delete[] p;
+  return new (std::align_val_t (64), std::nothrow) X1[4];
+}
+
+void warn_x1_array_mismatch ()
+{
+  {
+    X1 *p = new X1;
+    delete[] p;               // { dg-warning "'static void X1::operator delete \\\[]\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+  }
+  {
+    X1 *p = new X1[2];
+    delete p;                 // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+  }
+  {
+    X1 *p = new (std::align_val_t (32)) X1[2];
+    delete p;                 // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+  }
+  {
+    // The following requires optimization (see warn_x1_array_mismatch()).
+    X1 *p = new (std::nothrow) X1[3];
+    delete p;                 // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" "pr?????" { xfail *-*-* } }
+  }
+}
+
+#pragma GCC push_options
+#pragma GCC optimize "1"
+
+void warn_x1_nothrow_array_mismatch ()
+{
+  X1 *p = new (std::nothrow) X1[3];
+  delete p;                   // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+}
+
+#pragma GCC pop_options
+
+
+struct X2: X1
+{
+  X2 ();
+
+  void* operator new (size_t);
+  void operator delete (void*);
+};
+
+X2* nowarn_x2 ()
+{
+  X2 *p = new X2;
+  sink (p);
+  return new X2;
+}
+
+void warn_x2 ()
+{
+  X1 *p = new X2;             // { dg-message "returned from 'static void\\* X2::operator new\\(size_t\\)'" "note" }
+  sink (p);
+  delete p;                   // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+}
+
+namespace N {
+namespace NS {
+namespace NmSpc {
+namespace NameSpace {
+
+namespace dl {   // same name as operator delete
+namespace nw {   // and as operator new
+
+struct X3: X2
+{
+  X3 ();
+
+  void* operator new (size_t);
+  void operator delete (void*);
+};
+
+X3* nowarn_x3 ()
+{
+  X3 *p = new X3;
+  sink (p);
+  return new X3;
+}
+
+void warn_x3 ()
+{
+  X1 *p = new X3;             // { dg-message "returned from 'static void\\* N::NS::NmSpc::NameSpace::dl::nw::X3::operator new\\(size_t\\)'" "note" }
+  sink (p);
+  delete p;                   // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+}
+
+template <int N>
+struct X4: X2
+{
+  X4 ();
+
+  void* operator new (size_t);
+  void operator delete (void*);
+};
+
+void* nowarn_x4 ()
+{
+  X4<0> *p = new X4<0>;
+  sink (p);
+  return new X4<1>;
+}
+
+void warn_x4 ()
+{
+  X1 *p = new X4<1>;          // { dg-message "returned from 'static void\\* N::NS::NmSpc::NameSpace::dl::nw::X4<N>::operator new\\(size_t\\) \\\[with int N = 1]'" "note" }
+  sink (p);
+  delete p;                   // { dg-warning "'static void X1::operator delete\\(void\\*\\)' called on pointer returned from a mismatched allocation function" }
+}
+
+void warn_x4_inst_mismatch ()
+{
+  void *p = new X4<2>;        // { dg-message "returned from 'static void\\* N::NS::NmSpc::NameSpace::dl::nw::X4<N>::operator new\\(size_t\\) \\\[with int N = 2]'" "note" }
+  sink (p);
+  X4<3> *q = (X4<3>*)p;
+  delete q;                   // { dg-warning "'static void N::NS::NmSpc::NameSpace::dl::nw::X4<N>::operator delete\\(void\\*\\) \\\[with int N = 3]' called on pointer returned from a mismatched allocation function" }
+}
+
+}   // nw
+}   // dl
+}   // NameSpace
+}   // NmSpc
+}   // NS
+}   // N
diff --git a/libstdc++-v3/testsuite/ext/vstring/requirements/exception/basic.cc b/libstdc++-v3/testsuite/ext/vstring/requirements/exception/basic.cc
index 1f4ba020b3b..5036be50724 100644
--- a/libstdc++-v3/testsuite/ext/vstring/requirements/exception/basic.cc
+++ b/libstdc++-v3/testsuite/ext/vstring/requirements/exception/basic.cc
@@ -48,3 +48,7 @@ int main()
   value();
   return 0;
 }
+
+// The __versa_string destructor triggers a bogus -Wfree-nonheap-object
+// due to pr54202.
+// { dg-prune-output "\\\[-Wfree-nonheap-object" }
diff --git a/libstdc++-v3/testsuite/ext/vstring/requirements/exception/propagation_consistent.cc b/libstdc++-v3/testsuite/ext/vstring/requirements/exception/propagation_consistent.cc
index add7a922cdf..61e9aedb7e6 100644
--- a/libstdc++-v3/testsuite/ext/vstring/requirements/exception/propagation_consistent.cc
+++ b/libstdc++-v3/testsuite/ext/vstring/requirements/exception/propagation_consistent.cc
@@ -48,3 +48,7 @@ int main()
   value();
   return 0;
 }
+
+// The __versa_string destructor triggers a bogus -Wfree-nonheap-object
+// due to pr54202.
+// { dg-prune-output "\\\[-Wfree-nonheap-object" }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)
  2020-12-08 20:46 [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166) Martin Sebor
@ 2020-12-08 21:29 ` Martin Sebor
  2020-12-13 17:23 ` Jeff Law
  2023-06-07 15:01 ` Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)) Thomas Schwinge
  2 siblings, 0 replies; 9+ messages in thread
From: Martin Sebor @ 2020-12-08 21:29 UTC (permalink / raw)
  To: gcc-patches, Jeff Law

On 12/8/20 1:46 PM, Martin Sebor wrote:
> PR 98160 reports an ICE in pretty printer code called from the newly
> added -Wmismatched-new-delete.  The ICE is just a simple oversight,
> but much more interesting is the warning issued for the test case.
> It highlights an issue I didn't consider in the initial implementation:
> that inlining one of a pair of allocation/deallocation functions but
> not the other might lead to false positives when the inlined function
> calls another allocator that the deallocator isn't associated with.
> 
> In addition, tests for the changes exposed the overly simplistic
> nature of the detection of calls to mismatched forms of operator
> new and delete which fails to consider member operators, also
> resulting in false positives.
> 
> Finally, in a comment on the initial implementation Jonathan notes
> that the -Wmismatched-new-delete warning should trigger not only
> in user code but also in libstdc++ functions inlined into user code.
> I thought I had done that but as it turns out, the "standard code
> sequence" I put in place isn't sufficient to make this work.

I forgot to mention one other issue: the initial implementation is
also susceptible to false positives for calls to __builtin_free (and
__builtin_realloc) when the library function (i.e., free or realloc)
was associated with an allocator.  The patch also avoids those by
making the built-in handling more robust.  Since Glibc headers are
not allowed to declare symbols from other headers (e.g., <stdio.h>
is not allowed to declare free()), referring to the __builtin_xxx
forms of the functions might be the only way to associate, say,
tempnam with free.  I'm hoping to add this for the next Glibc
release.

> The attached changes avoid the false positives a) by ignoring (with
> a warning) the new form of the malloc attribute on inline functions,
> and disabling the inlining of others by implicitly adding attribute
> noinline to their declaration, and b) by making more robust
> the detection of mismatched operators new and delete.  Furthermore,
> the patch also arranges for the warning to trigger even for inlined
> calls to functions defined in system headers.
> 
> To make review a little (marginally) easier the change are two files:
> 1) gcc-98166-1.diff: introduces valid_new_delete_pair_p and
> tree_inlined_location.
> 2) gcc-98166-2.diff: adjusts the atrribute/warning implementation .
> 
> Tested on x86_64-linux.
> 
> Martin


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)
  2020-12-08 20:46 [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166) Martin Sebor
  2020-12-08 21:29 ` Martin Sebor
@ 2020-12-13 17:23 ` Jeff Law
  2020-12-14 21:05   ` Martin Sebor
  2023-06-07 15:01 ` Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)) Thomas Schwinge
  2 siblings, 1 reply; 9+ messages in thread
From: Jeff Law @ 2020-12-13 17:23 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches



On 12/8/20 1:46 PM, Martin Sebor wrote:
> PR 98160 reports an ICE in pretty printer code called from the newly
> added -Wmismatched-new-delete.  The ICE is just a simple oversight,
> but much more interesting is the warning issued for the test case.
> It highlights an issue I didn't consider in the initial implementation:
> that inlining one of a pair of allocation/deallocation functions but
> not the other might lead to false positives when the inlined function
> calls another allocator that the deallocator isn't associated with.
>
> In addition, tests for the changes exposed the overly simplistic
> nature of the detection of calls to mismatched forms of operator
> new and delete which fails to consider member operators, also
> resulting in false positives.
>
> Finally, in a comment on the initial implementation Jonathan notes
> that the -Wmismatched-new-delete warning should trigger not only
> in user code but also in libstdc++ functions inlined into user code.
> I thought I had done that but as it turns out, the "standard code
> sequence" I put in place isn't sufficient to make this work.
>
> The attached changes avoid the false positives a) by ignoring (with
> a warning) the new form of the malloc attribute on inline functions,
> and disabling the inlining of others by implicitly adding attribute
> noinline to their declaration, and b) by making more robust
> the detection of mismatched operators new and delete.  Furthermore,
> the patch also arranges for the warning to trigger even for inlined
> calls to functions defined in system headers.
>
> To make review a little (marginally) easier the change are two files:
> 1) gcc-98166-1.diff: introduces valid_new_delete_pair_p and
> tree_inlined_location.
> 2) gcc-98166-2.diff: adjusts the atrribute/warning implementation .
>
> Tested on x86_64-linux.
>
> Martin
>
> gcc-98166-1.diff
>
> Introduce an overload of valid_new_delete_pair_p and tree_inlined_location.
>
> gcc/ChangeLog:
>
> 	* tree-ssa-dce.c (valid_new_delete_pair_p): Factor code out into
> 	valid_new_delete_pair_p in tree.c.
> 	* tree.c (tree_inlined_location): Define new function.
> 	(valid_new_delete_pair_p): Define.
> 	* tree.h (tree_inlined_location): Declare.
> 	(valid_new_delete_pair_p): Declare.
OK


>
> gcc-98166-2.diff
>
> Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160).
>
> Resolves:
> PR middle-end/98166 - bogus -Wmismatched-dealloc on user-defined allocator and inlining
> PR c++/57111 - 57111 - Generalize -Wfree-nonheap-object to delete
> PR middle-end/98160 - ICE in default_tree_printer at gcc/tree-diagnostic.c:270
>
> gcc/ChangeLog:
>
> 	PR middle-end/98166
> 	PR c++/57111
> 	PR middle-end/98160
> 	* builtins.c (call_dealloc_p): Remove unused function.
> 	(new_delete_mismatch_p): Call valid_new_delete_pair_p and rework.
> 	(matching_alloc_calls_p): Handle built-in deallocation functions.
> 	(warn_dealloc_offset): Corrct the handling of user-defined operators
> 	delete.
> 	(maybe_emit_free_warning): Avoid assuming expression is a decl.
> 	Simplify.
> 	* doc/extend.texi (attribute malloc): Update.
>
> gcc/c-family/ChangeLog:
>
> 	PR middle-end/98166
> 	PR c++/57111
> 	PR middle-end/98160
> 	* c-attribs.c (handle_malloc_attribute): Implicitly add attribute
> 	noinline to functions not declared inline and warn on those.
>
> libstdc++-v3/ChangeLog:
> 	* testsuite/ext/vstring/requirements/exception/basic.cc: Suppress
> 	a false positive warning.
> 	* testsuite/ext/vstring/requirements/exception/propagation_consistent.cc:
> 	  Same.
>
> gcc/testsuite/ChangeLog:
>
> 	PR middle-end/98166
> 	PR c++/57111
> 	PR middle-end/98160
> 	* g++.dg/warn/Wmismatched-dealloc-2.C: Adjust test of expected warning.
> 	* g++.dg/warn/Wmismatched-new-delete.C: Same.
> 	* gcc.dg/Wmismatched-dealloc.c: Same.
> 	* c-c++-common/Wfree-nonheap-object-2.c: New test.
> 	* c-c++-common/Wfree-nonheap-object-3.c: New test.
> 	* c-c++-common/Wfree-nonheap-object.c: New test.
> 	* c-c++-common/Wmismatched-dealloc.c: New test.
> 	* g++.dg/warn/Wfree-nonheap-object-3.C: New test.
> 	* g++.dg/warn/Wfree-nonheap-object-4.C: New test.
> 	* g++.dg/warn/Wmismatched-new-delete-2.C: New test.
OK, but there's a follow-up as noted below:


>
>  
> diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
> index 7ecc99a325c..3aea02fa63d 100644
> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
Please fix the non-unique testnames in this file.  This can be done as a
separate follow-up patch as they're pre-existing.

diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
> index ed1090be5c5..fc07149995d 100644
> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
And in this file.

Jeff


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)
  2020-12-13 17:23 ` Jeff Law
@ 2020-12-14 21:05   ` Martin Sebor
  2020-12-14 23:08     ` Jeff Law
  0 siblings, 1 reply; 9+ messages in thread
From: Martin Sebor @ 2020-12-14 21:05 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On 12/13/20 10:23 AM, Jeff Law wrote:
> 
> 
> On 12/8/20 1:46 PM, Martin Sebor wrote:
>> PR 98160 reports an ICE in pretty printer code called from the newly
>> added -Wmismatched-new-delete.  The ICE is just a simple oversight,
>> but much more interesting is the warning issued for the test case.
>> It highlights an issue I didn't consider in the initial implementation:
>> that inlining one of a pair of allocation/deallocation functions but
>> not the other might lead to false positives when the inlined function
>> calls another allocator that the deallocator isn't associated with.
>>
>> In addition, tests for the changes exposed the overly simplistic
>> nature of the detection of calls to mismatched forms of operator
>> new and delete which fails to consider member operators, also
>> resulting in false positives.
>>
>> Finally, in a comment on the initial implementation Jonathan notes
>> that the -Wmismatched-new-delete warning should trigger not only
>> in user code but also in libstdc++ functions inlined into user code.
>> I thought I had done that but as it turns out, the "standard code
>> sequence" I put in place isn't sufficient to make this work.
>>
>> The attached changes avoid the false positives a) by ignoring (with
>> a warning) the new form of the malloc attribute on inline functions,
>> and disabling the inlining of others by implicitly adding attribute
>> noinline to their declaration, and b) by making more robust
>> the detection of mismatched operators new and delete.  Furthermore,
>> the patch also arranges for the warning to trigger even for inlined
>> calls to functions defined in system headers.
>>
>> To make review a little (marginally) easier the change are two files:
>> 1) gcc-98166-1.diff: introduces valid_new_delete_pair_p and
>> tree_inlined_location.
>> 2) gcc-98166-2.diff: adjusts the atrribute/warning implementation .
>>
>> Tested on x86_64-linux.
>>
>> Martin
>>
>> gcc-98166-1.diff
>>
>> Introduce an overload of valid_new_delete_pair_p and tree_inlined_location.
>>
>> gcc/ChangeLog:
>>
>> 	* tree-ssa-dce.c (valid_new_delete_pair_p): Factor code out into
>> 	valid_new_delete_pair_p in tree.c.
>> 	* tree.c (tree_inlined_location): Define new function.
>> 	(valid_new_delete_pair_p): Define.
>> 	* tree.h (tree_inlined_location): Declare.
>> 	(valid_new_delete_pair_p): Declare.
> OK
> 
> 
>>
>> gcc-98166-2.diff
>>
>> Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160).
>>
>> Resolves:
>> PR middle-end/98166 - bogus -Wmismatched-dealloc on user-defined allocator and inlining
>> PR c++/57111 - 57111 - Generalize -Wfree-nonheap-object to delete
>> PR middle-end/98160 - ICE in default_tree_printer at gcc/tree-diagnostic.c:270
>>
>> gcc/ChangeLog:
>>
>> 	PR middle-end/98166
>> 	PR c++/57111
>> 	PR middle-end/98160
>> 	* builtins.c (call_dealloc_p): Remove unused function.
>> 	(new_delete_mismatch_p): Call valid_new_delete_pair_p and rework.
>> 	(matching_alloc_calls_p): Handle built-in deallocation functions.
>> 	(warn_dealloc_offset): Corrct the handling of user-defined operators
>> 	delete.
>> 	(maybe_emit_free_warning): Avoid assuming expression is a decl.
>> 	Simplify.
>> 	* doc/extend.texi (attribute malloc): Update.
>>
>> gcc/c-family/ChangeLog:
>>
>> 	PR middle-end/98166
>> 	PR c++/57111
>> 	PR middle-end/98160
>> 	* c-attribs.c (handle_malloc_attribute): Implicitly add attribute
>> 	noinline to functions not declared inline and warn on those.
>>
>> libstdc++-v3/ChangeLog:
>> 	* testsuite/ext/vstring/requirements/exception/basic.cc: Suppress
>> 	a false positive warning.
>> 	* testsuite/ext/vstring/requirements/exception/propagation_consistent.cc:
>> 	  Same.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	PR middle-end/98166
>> 	PR c++/57111
>> 	PR middle-end/98160
>> 	* g++.dg/warn/Wmismatched-dealloc-2.C: Adjust test of expected warning.
>> 	* g++.dg/warn/Wmismatched-new-delete.C: Same.
>> 	* gcc.dg/Wmismatched-dealloc.c: Same.
>> 	* c-c++-common/Wfree-nonheap-object-2.c: New test.
>> 	* c-c++-common/Wfree-nonheap-object-3.c: New test.
>> 	* c-c++-common/Wfree-nonheap-object.c: New test.
>> 	* c-c++-common/Wmismatched-dealloc.c: New test.
>> 	* g++.dg/warn/Wfree-nonheap-object-3.C: New test.
>> 	* g++.dg/warn/Wfree-nonheap-object-4.C: New test.
>> 	* g++.dg/warn/Wmismatched-new-delete-2.C: New test.
> OK, but there's a follow-up as noted below:
> 
> 
>>
>>   
>> diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>> index 7ecc99a325c..3aea02fa63d 100644
>> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
> Please fix the non-unique testnames in this file.  This can be done as a
> separate follow-up patch as they're pre-existing.
> 
> diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
> b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>> index ed1090be5c5..fc07149995d 100644
>> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
> And in this file.

I made an additional tweak to better handle Glibc headers and
committed r11-6028.  I don't see any non-unique names in either
of the tests (or any others in the patch).

Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)
  2020-12-14 21:05   ` Martin Sebor
@ 2020-12-14 23:08     ` Jeff Law
  0 siblings, 0 replies; 9+ messages in thread
From: Jeff Law @ 2020-12-14 23:08 UTC (permalink / raw)
  To: Martin Sebor, gcc-patches



On 12/14/20 2:05 PM, Martin Sebor wrote:
> On 12/13/20 10:23 AM, Jeff Law wrote:
>>
>>
>> On 12/8/20 1:46 PM, Martin Sebor wrote:
>>> PR 98160 reports an ICE in pretty printer code called from the newly
>>> added -Wmismatched-new-delete.  The ICE is just a simple oversight,
>>> but much more interesting is the warning issued for the test case.
>>> It highlights an issue I didn't consider in the initial implementation:
>>> that inlining one of a pair of allocation/deallocation functions but
>>> not the other might lead to false positives when the inlined function
>>> calls another allocator that the deallocator isn't associated with.
>>>
>>> In addition, tests for the changes exposed the overly simplistic
>>> nature of the detection of calls to mismatched forms of operator
>>> new and delete which fails to consider member operators, also
>>> resulting in false positives.
>>>
>>> Finally, in a comment on the initial implementation Jonathan notes
>>> that the -Wmismatched-new-delete warning should trigger not only
>>> in user code but also in libstdc++ functions inlined into user code.
>>> I thought I had done that but as it turns out, the "standard code
>>> sequence" I put in place isn't sufficient to make this work.
>>>
>>> The attached changes avoid the false positives a) by ignoring (with
>>> a warning) the new form of the malloc attribute on inline functions,
>>> and disabling the inlining of others by implicitly adding attribute
>>> noinline to their declaration, and b) by making more robust
>>> the detection of mismatched operators new and delete.  Furthermore,
>>> the patch also arranges for the warning to trigger even for inlined
>>> calls to functions defined in system headers.
>>>
>>> To make review a little (marginally) easier the change are two files:
>>> 1) gcc-98166-1.diff: introduces valid_new_delete_pair_p and
>>> tree_inlined_location.
>>> 2) gcc-98166-2.diff: adjusts the atrribute/warning implementation .
>>>
>>> Tested on x86_64-linux.
>>>
>>> Martin
>>>
>>> gcc-98166-1.diff
>>>
>>> Introduce an overload of valid_new_delete_pair_p and
>>> tree_inlined_location.
>>>
>>> gcc/ChangeLog:
>>>
>>>     * tree-ssa-dce.c (valid_new_delete_pair_p): Factor code out into
>>>     valid_new_delete_pair_p in tree.c.
>>>     * tree.c (tree_inlined_location): Define new function.
>>>     (valid_new_delete_pair_p): Define.
>>>     * tree.h (tree_inlined_location): Declare.
>>>     (valid_new_delete_pair_p): Declare.
>> OK
>>
>>
>>>
>>> gcc-98166-2.diff
>>>
>>> Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR
>>> c++/57111, PR middle-end/98160).
>>>
>>> Resolves:
>>> PR middle-end/98166 - bogus -Wmismatched-dealloc on user-defined
>>> allocator and inlining
>>> PR c++/57111 - 57111 - Generalize -Wfree-nonheap-object to delete
>>> PR middle-end/98160 - ICE in default_tree_printer at
>>> gcc/tree-diagnostic.c:270
>>>
>>> gcc/ChangeLog:
>>>
>>>     PR middle-end/98166
>>>     PR c++/57111
>>>     PR middle-end/98160
>>>     * builtins.c (call_dealloc_p): Remove unused function.
>>>     (new_delete_mismatch_p): Call valid_new_delete_pair_p and rework.
>>>     (matching_alloc_calls_p): Handle built-in deallocation functions.
>>>     (warn_dealloc_offset): Corrct the handling of user-defined
>>> operators
>>>     delete.
>>>     (maybe_emit_free_warning): Avoid assuming expression is a decl.
>>>     Simplify.
>>>     * doc/extend.texi (attribute malloc): Update.
>>>
>>> gcc/c-family/ChangeLog:
>>>
>>>     PR middle-end/98166
>>>     PR c++/57111
>>>     PR middle-end/98160
>>>     * c-attribs.c (handle_malloc_attribute): Implicitly add attribute
>>>     noinline to functions not declared inline and warn on those.
>>>
>>> libstdc++-v3/ChangeLog:
>>>     * testsuite/ext/vstring/requirements/exception/basic.cc: Suppress
>>>     a false positive warning.
>>>     *
>>> testsuite/ext/vstring/requirements/exception/propagation_consistent.cc:
>>>       Same.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>     PR middle-end/98166
>>>     PR c++/57111
>>>     PR middle-end/98160
>>>     * g++.dg/warn/Wmismatched-dealloc-2.C: Adjust test of expected
>>> warning.
>>>     * g++.dg/warn/Wmismatched-new-delete.C: Same.
>>>     * gcc.dg/Wmismatched-dealloc.c: Same.
>>>     * c-c++-common/Wfree-nonheap-object-2.c: New test.
>>>     * c-c++-common/Wfree-nonheap-object-3.c: New test.
>>>     * c-c++-common/Wfree-nonheap-object.c: New test.
>>>     * c-c++-common/Wmismatched-dealloc.c: New test.
>>>     * g++.dg/warn/Wfree-nonheap-object-3.C: New test.
>>>     * g++.dg/warn/Wfree-nonheap-object-4.C: New test.
>>>     * g++.dg/warn/Wmismatched-new-delete-2.C: New test.
>> OK, but there's a follow-up as noted below:
>>
>>
>>>
>>>   diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>>> b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>>> index 7ecc99a325c..3aea02fa63d 100644
>>> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>>> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-dealloc-2.C
>> Please fix the non-unique testnames in this file.  This can be done as a
>> separate follow-up patch as they're pre-existing.
>>
>> diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>> b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>>> index ed1090be5c5..fc07149995d 100644
>>> --- a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>>> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete.C
>> And in this file.
>
> I made an additional tweak to better handle Glibc headers and
> committed r11-6028.  I don't see any non-unique names in either
> of the tests (or any others in the patch).
You're right.  My bad.   There are days when I hate unidiff.  It's only
been 20 years of daily use and my brain still handles context diffs better.

jeff


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166))
  2020-12-08 20:46 [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166) Martin Sebor
  2020-12-08 21:29 ` Martin Sebor
  2020-12-13 17:23 ` Jeff Law
@ 2023-06-07 15:01 ` Thomas Schwinge
  2023-06-07 17:13   ` Mike Stump
  2023-06-15  0:50   ` [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c -std=gnu++98 (test for warnings, line 45) on Linux/x86_64 haochen.jiang
  2 siblings, 2 replies; 9+ messages in thread
From: Thomas Schwinge @ 2023-06-07 15:01 UTC (permalink / raw)
  To: gcc-patches, Rainer Orth, Mike Stump; +Cc: Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 6746 bytes --]

Hi!

On 2020-12-08T13:46:32-0700, Martin Sebor via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> The attached changes [...]

... eventually became commit fe7f75cf16783589eedbab597e6d0b8d35d7e470
"Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160)".

>       * c-c++-common/Wfree-nonheap-object-2.c: New test.
>       * c-c++-common/Wfree-nonheap-object-3.c: New test.
>       * c-c++-common/Wfree-nonheap-object.c: New test.

OK to push the attached
"Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'"?


Grüße
 Thomas


> diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
> new file mode 100644
> index 00000000000..0aedf1babbc
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
> @@ -0,0 +1,52 @@
> +/* PR middle-end/98166: bogus -Wmismatched-dealloc on user-defined allocator
> +   and inlining
> +   Verify that the allocator can be declared inline without a warning when
> +   it's associated with a standard deallocator.  Associating an inline
> +   deallocator with an allocator would cause false positives when the former
> +   calls a deallocation function the allocator isn't associated with, so
> +   that triggers a warning on declaration.
> +   { dg-do compile }
> +   { dg-options "-O2 -Wall" } */
> +
> +__attribute__ ((malloc (__builtin_free)))
> +inline int*
> +alloc_int (int n)
> +{
> +  return (int*)__builtin_malloc (n + sizeof (int));
> +}
> +
> +void test_nowarn_int (int n)
> +{
> +  {
> +    int *p = alloc_int (n);
> +    __builtin_free (p);
> +  }
> +
> +  {
> +    int *p = alloc_int (n);
> +    __builtin_free (p + 1);   // { dg-warning "\\\[-Wfree-nonheap-object" }
> +  }
> +}
> +
> +
> +inline void
> +dealloc_long (long *p)
> +{
> +  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +}
> +
> +__attribute__ ((malloc (dealloc_long)))
> +long* alloc_long (int);       // { dg-warning "'malloc \\\(dealloc_long\\\)' attribute ignored with deallocation functions declared 'inline'" }
> +
> +void test_nowarn_long (int n)
> +{
> +  {
> +    long *p = alloc_long (n);
> +    dealloc_long (p);
> +  }
> +
> +  {
> +    long *p = alloc_long (n);
> +    dealloc_long (p + 1);
> +  }
> +}
> diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
> new file mode 100644
> index 00000000000..41a5b50362e
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
> @@ -0,0 +1,70 @@
> +/* PR middle-end/98166: bogus -Wmismatched-dealloc on user-defined allocator
> +   and inlining
> +   Verify that without inlining, both the allocator and the deallocator
> +   can be declared inline without a warning and that mismatched calls are
> +   detected, but that declaring them always_inline does trigger a warning.
> +   { dg-do compile }
> +   { dg-options "-Wall" } */
> +
> +__attribute__ ((malloc (__builtin_free)))
> +inline int*
> +alloc_int (int n)
> +{
> +  return (int*)__builtin_malloc (n + sizeof (int));
> +}
> +
> +void test_nowarn_int (int n)
> +{
> +  {
> +    int *p = alloc_int (n);
> +    __builtin_free (p);
> +  }
> +
> +  {
> +    int *p = alloc_int (n);
> +    __builtin_free (p + 1);   // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +  }
> +}
> +
> +
> +inline void
> +dealloc_long (long *p) { __builtin_free (p); }
> +
> +__attribute__ ((malloc (dealloc_long)))
> +long* alloc_long (int);
> +
> +void test_nowarn_long (int n)
> +{
> +  {
> +    long *p = alloc_long (n);
> +    dealloc_long (p);
> +  }
> +
> +  {
> +    long *p = alloc_long (n);
> +    dealloc_long (p + 1);     // { dg-warning "'dealloc_long' called on pointer 'p|<unknown>' with nonzero offset" }
> +  }
> +}
> +
> +
> +inline __attribute__ ((always_inline)) void
> +dealloc_float (float *p)      // { dg-message "deallocation function declared here" }
> +{
> +  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +}
> +
> +__attribute__ ((malloc (dealloc_float)))
> +float* alloc_float (int);     // { dg-warning "'malloc \\(dealloc_float\\)' attribute ignored with deallocation functions declared 'inline'" }
> +
> +void test_nowarn_float (int n)
> +{
> +  {
> +    float *p = alloc_float (n);
> +    dealloc_float (p);
> +  }
> +
> +  {
> +    float *p = alloc_float (n);
> +    dealloc_float (p + 2);
> +  }
> +}
> diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
> new file mode 100644
> index 00000000000..dfbb296e9a7
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
> @@ -0,0 +1,50 @@
> +/* Verify that built-in forms of functions can be used interchangeably
> +   with their ordinary (library) forms in attribute malloc.
> +   { dg-do compile }
> +   { dg-options "-Wall" } */
> +
> +char* f (void) __attribute__ ((malloc (__builtin_free)));
> +
> +#if __cplusplus
> +extern "C" {
> +#endif
> +
> +void free (void*);
> +
> +#if __cplusplus
> +}
> +#endif
> +
> +char* g (void) __attribute__ ((malloc (free)));
> +
> +
> +void test_nowarm (void)
> +{
> +  char *p = f ();
> +  free (p);
> +
> +  p = g ();
> +  free (p);
> +
> +  p = f ();
> +  __builtin_free (p);
> +
> +  p = g ();
> +  __builtin_free (p);
> +}
> +
> +
> +void test_warn (void)
> +{
> +  char *p = f ();
> +  free (p + 1);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +
> +  p = g ();
> +  free (p + 2);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +
> +  p = f ();
> +  __builtin_free (p + 3);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +
> +  p = g ();
> +  __builtin_free (p + 4);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
> +}


-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Tighten-dg-warning-alternatives-in-c-c-common-Wfree-.patch --]
[-- Type: text/x-diff, Size: 4992 bytes --]

From d9039d3d5b410075e2afa3a5a635f7399f072edd Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 7 Jun 2023 16:24:26 +0200
Subject: [PATCH] Tighten 'dg-warning' alternatives in
 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'

..., added in commit fe7f75cf16783589eedbab597e6d0b8d35d7e470
"Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160)".

These use alternatives like, for example, "AB|CDE|FG", but what really must've
been meant is "A(B|C)D(E|F)G".  The former variant also does "work": it matches
any of "AB", or "CDE", or "FG", which are components of the latter variant.
(That means, the former variant matches too loosely.)

	gcc/testsuite/
	* c-c++-common/Wfree-nonheap-object-2.c: Tighten 'dg-warning'
	alternatives.
	* c-c++-common/Wfree-nonheap-object-3.c: Likewise.
	* c-c++-common/Wfree-nonheap-object.c: Likewise.
---
 gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c | 2 +-
 gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c | 6 +++---
 gcc/testsuite/c-c++-common/Wfree-nonheap-object.c   | 8 ++++----
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
index 0aedf1babbc..a2dbd181e33 100644
--- a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-2.c
@@ -32,7 +32,7 @@ void test_nowarn_int (int n)
 inline void
 dealloc_long (long *p)
 {
-  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  __builtin_free (p);         // { dg-warning "'(__builtin_free|void __builtin_free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 }
 
 __attribute__ ((malloc (dealloc_long)))
diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
index 41a5b50362e..8f20de8455f 100644
--- a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
@@ -22,7 +22,7 @@ void test_nowarn_int (int n)
 
   {
     int *p = alloc_int (n);
-    __builtin_free (p + 1);   // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+    __builtin_free (p + 1);   // { dg-warning "'(__builtin_free|void __builtin_free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
   }
 }
 
@@ -42,7 +42,7 @@ void test_nowarn_long (int n)
 
   {
     long *p = alloc_long (n);
-    dealloc_long (p + 1);     // { dg-warning "'dealloc_long' called on pointer 'p|<unknown>' with nonzero offset" }
+    dealloc_long (p + 1);     // { dg-warning "'dealloc_long' called on pointer '(p|<unknown>)' with nonzero offset" }
   }
 }
 
@@ -50,7 +50,7 @@ void test_nowarn_long (int n)
 inline __attribute__ ((always_inline)) void
 dealloc_float (float *p)      // { dg-message "deallocation function declared here" }
 {
-  __builtin_free (p);         // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  __builtin_free (p);         // { dg-warning "'(__builtin_free|void __builtin_free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 }
 
 __attribute__ ((malloc (dealloc_float)))
diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
index dfbb296e9a7..5f1e3fb28f3 100644
--- a/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object.c
@@ -37,14 +37,14 @@ void test_nowarm (void)
 void test_warn (void)
 {
   char *p = f ();
-  free (p + 1);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  free (p + 1);               // { dg-warning "'(free|void free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 
   p = g ();
-  free (p + 2);               // { dg-warning "'free|void free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  free (p + 2);               // { dg-warning "'(free|void free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 
   p = f ();
-  __builtin_free (p + 3);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  __builtin_free (p + 3);     // { dg-warning "'(__builtin_free|void __builtin_free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 
   p = g ();
-  __builtin_free (p + 4);     // { dg-warning "'__builtin_free|void __builtin_free\\(void\\*\\)' called on pointer 'p|<unknown>' with nonzero offset" }
+  __builtin_free (p + 4);     // { dg-warning "'(__builtin_free|void __builtin_free\\(void\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
 }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166))
  2023-06-07 15:01 ` Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)) Thomas Schwinge
@ 2023-06-07 17:13   ` Mike Stump
  2023-06-15  0:50   ` [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c -std=gnu++98 (test for warnings, line 45) on Linux/x86_64 haochen.jiang
  1 sibling, 0 replies; 9+ messages in thread
From: Mike Stump @ 2023-06-07 17:13 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Rainer Orth, Martin Sebor

On Jun 7, 2023, at 8:01 AM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> On 2020-12-08T13:46:32-0700, Martin Sebor via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> The attached changes [...]
> 
> ... eventually became commit fe7f75cf16783589eedbab597e6d0b8d35d7e470
> "Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160)".
> 
>>      * c-c++-common/Wfree-nonheap-object-2.c: New test.
>>      * c-c++-common/Wfree-nonheap-object-3.c: New test.
>>      * c-c++-common/Wfree-nonheap-object.c: New test.
> 
> OK to push the attached
> "Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'"?

Ok.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 45) on Linux/x86_64
@ 2023-06-15  0:50   ` haochen.jiang
  2023-06-15  7:23     ` Thomas Schwinge
  0 siblings, 1 reply; 9+ messages in thread
From: haochen.jiang @ 2023-06-15  0:50 UTC (permalink / raw)
  To: thomas, gcc-regression, gcc-patches, haochen.jiang

On Linux/x86_64,

9c03391ba447ff86038d6a34c90ae737c3915b5f is the first bad commit
commit 9c03391ba447ff86038d6a34c90ae737c3915b5f
Author: Thomas Schwinge <thomas@codesourcery.com>
Date:   Wed Jun 7 16:24:26 2023 +0200

    Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'

caused

FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++14 (test for excess errors)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++14  (test for warnings, line 45)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++17 (test for excess errors)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++17  (test for warnings, line 45)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++20 (test for excess errors)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++20  (test for warnings, line 45)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98 (test for excess errors)
FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 45)

with GCC configured with

../../gcc/configure --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-1805/usr --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet --without-isl --enable-libmpx x86_64-linux --disable-bootstrap

To reproduce:

$ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m32}'"
$ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m32\ -march=cascadelake}'"
$ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m64}'"
$ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m64\ -march=cascadelake}'"

(Please do not reply to this email, for question about this report, contact me at haochen dot jiang at intel.com)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 45) on Linux/x86_64
  2023-06-15  0:50   ` [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c -std=gnu++98 (test for warnings, line 45) on Linux/x86_64 haochen.jiang
@ 2023-06-15  7:23     ` Thomas Schwinge
  0 siblings, 0 replies; 9+ messages in thread
From: Thomas Schwinge @ 2023-06-15  7:23 UTC (permalink / raw)
  To: gcc-patches
  Cc: gcc-regression, haochen.jiang, Rainer Orth, Mike Stump, Martin Sebor

[-- Attachment #1: Type: text/plain, Size: 2790 bytes --]

Hi!

On 2023-06-15T08:50:59+0800, "haochen.jiang via Gcc-patches" <gcc-patches@gcc.gnu.org> wrote:
> On Linux/x86_64,

Actually: generally...

> 9c03391ba447ff86038d6a34c90ae737c3915b5f is the first bad commit
> commit 9c03391ba447ff86038d6a34c90ae737c3915b5f
> Author: Thomas Schwinge <thomas@codesourcery.com>
> Date:   Wed Jun 7 16:24:26 2023 +0200
>
>     Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'
>
> caused
>
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++14 (test for excess errors)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++14  (test for warnings, line 45)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++17 (test for excess errors)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++17  (test for warnings, line 45)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++20 (test for excess errors)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++20  (test for warnings, line 45)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98 (test for excess errors)
> FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 45)

Indeed.  Sorry -- not sure how that escaped my testing.  I already did
have the fix in a different Git commit (but not in my testing build).
Pushed to master branch commit df071fbd467f0cb3711119ef41d74792fc5e6c8c
"Fix 'dg-warning' in 'c-c++-common/Wfree-nonheap-object-3.c' for C++",
see attached.


Grüße
 Thomas


> with GCC configured with
>
> ../../gcc/configure --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-1805/usr --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet --without-isl --enable-libmpx x86_64-linux --disable-bootstrap
>
> To reproduce:
>
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m32}'"
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m32\ -march=cascadelake}'"
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m64}'"
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=c-c++-common/Wfree-nonheap-object-3.c --target_board='unix{-m64\ -march=cascadelake}'"
>
> (Please do not reply to this email, for question about this report, contact me at haochen dot jiang at intel.com)


-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-dg-warning-in-c-c-common-Wfree-nonheap-object-3..patch --]
[-- Type: text/x-diff, Size: 3909 bytes --]

From df071fbd467f0cb3711119ef41d74792fc5e6c8c Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 7 Jun 2023 17:12:01 +0200
Subject: [PATCH] Fix 'dg-warning' in 'c-c++-common/Wfree-nonheap-object-3.c'
 for C++

    [...]/c-c++-common/Wfree-nonheap-object-3.c:57:24: warning: 'malloc (dealloc_float)' attribute ignored with deallocation functions declared 'inline' [-Wattributes]
    [...]/c-c++-common/Wfree-nonheap-object-3.c:51:1: note: deallocation function declared here
    [...]/c-c++-common/Wfree-nonheap-object-3.c: In function 'void test_nowarn_int(int)':
    [...]/c-c++-common/Wfree-nonheap-object-3.c:25:20: warning: 'void __builtin_free(void*)' called on pointer 'p' with nonzero offset 4 [-Wfree-nonheap-object]
    [...]/c-c++-common/Wfree-nonheap-object-3.c:24:24: note: returned from 'int* alloc_int(int)'
    [...]/c-c++-common/Wfree-nonheap-object-3.c: In function 'void test_nowarn_long(int)':
    [...]/c-c++-common/Wfree-nonheap-object-3.c:45:18: warning: 'void dealloc_long(long int*)' called on pointer '<unknown>' with nonzero offset 8 [-Wfree-nonheap-object]
    [...]/c-c++-common/Wfree-nonheap-object-3.c:44:26: note: returned from 'long int* alloc_long(int)'
    In function 'void dealloc_float(float*)',
        inlined from 'void test_nowarn_float(int)' at [...]/c-c++-common/Wfree-nonheap-object-3.c:68:19:
    [...]/c-c++-common/Wfree-nonheap-object-3.c:53:18: warning: 'void __builtin_free(void*)' called on pointer '<unknown>' with nonzero offset 8 [-Wfree-nonheap-object]
    [...]/c-c++-common/Wfree-nonheap-object-3.c: In function 'void test_nowarn_float(int)':
    [...]/c-c++-common/Wfree-nonheap-object-3.c:67:28: note: returned from 'float* alloc_float(int)'
    PASS: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 25)
    FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 45)
    PASS: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 51)
    PASS: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 53)
    PASS: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98  (test for warnings, line 57)
    FAIL: c-c++-common/Wfree-nonheap-object-3.c  -std=gnu++98 (test for excess errors)
    Excess errors:
    [...]/c-c++-common/Wfree-nonheap-object-3.c:45:18: warning: 'void dealloc_long(long int*)' called on pointer '<unknown>' with nonzero offset 8 [-Wfree-nonheap-object]

..., that is: decorated 'void dealloc_long(long int*)' instead of plain
'dealloc_long' -- similar to how all the other 'dg-warning's allow for the
decorated function signature in addition to the plain one.

This issue was latent since the test case was added in
commit fe7f75cf16783589eedbab597e6d0b8d35d7e470
"Correct/improve maybe_emit_free_warning (PR middle-end/98166, PR c++/57111, PR middle-end/98160)",
and was finally exposed by my recent
commit 9c03391ba447ff86038d6a34c90ae737c3915b5f
"Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c'".

	gcc/testsuite/
	* c-c++-common/Wfree-nonheap-object-3.c: Fix 'dg-warning' for C++.
---
 gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
index 8f20de8455fa..23d89a31454e 100644
--- a/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
+++ b/gcc/testsuite/c-c++-common/Wfree-nonheap-object-3.c
@@ -42,7 +42,7 @@ void test_nowarn_long (int n)
 
   {
     long *p = alloc_long (n);
-    dealloc_long (p + 1);     // { dg-warning "'dealloc_long' called on pointer '(p|<unknown>)' with nonzero offset" }
+    dealloc_long (p + 1);     // { dg-warning "'(dealloc_long|void dealloc_long\\(long int\\*\\))' called on pointer '(p|<unknown>)' with nonzero offset" }
   }
 }
 
-- 
2.39.2


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-06-15  7:24 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-08 20:46 [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166) Martin Sebor
2020-12-08 21:29 ` Martin Sebor
2020-12-13 17:23 ` Jeff Law
2020-12-14 21:05   ` Martin Sebor
2020-12-14 23:08     ` Jeff Law
2023-06-07 15:01 ` Tighten 'dg-warning' alternatives in 'c-c++-common/Wfree-nonheap-object{,-2,-3}.c' (was: [PATCH] correct -Wmismatched-new-delete (PR 98160, 98166)) Thomas Schwinge
2023-06-07 17:13   ` Mike Stump
2023-06-15  0:50   ` [r14-1805 Regression] FAIL: c-c++-common/Wfree-nonheap-object-3.c -std=gnu++98 (test for warnings, line 45) on Linux/x86_64 haochen.jiang
2023-06-15  7:23     ` Thomas Schwinge

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).