diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index c7b567ba7abd12be6e7887b5ea44c0501c312413..2242524cd3e20eb2edb3ed0ea894b5f23a5203a1 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1935,6 +1935,10 @@ Winvalid-imported-macros
 C++ ObjC++ Var(warn_imported_macros) Warning
 Warn about macros that have conflicting header units definitions.
 
+Wcompare-distinct-pointer-types
+C ObjC Var(warn_compare_distinct_pointer_types) Warning Init(1)
+Warn if pointers of distinct types are compared without a cast.
+
 flang-info-include-translate
 C++ Var(note_include_translate_yes)
 Note #include directives translated to import declarations.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 6f2fff51683a449d528ee18421897b5c343f52d2..e6ddf37d41200de8011934fa31aea5fad3d8516c 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -12772,7 +12772,7 @@ build_binary_op (location_t location, enum tree_code code,
 	  else
 	    /* Avoid warning about the volatile ObjC EH puts on decls.  */
 	    if (!objc_ok)
-	      pedwarn (location, 0,
+	      pedwarn (location, OPT_Wcompare_distinct_pointer_types,
 		       "comparison of distinct pointer types lacks a cast");
 
 	  if (result_type == NULL_TREE)
@@ -12912,8 +12912,8 @@ build_binary_op (location_t location, enum tree_code code,
 	      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
 	      result_type = build_pointer_type
 			      (build_qualified_type (void_type_node, qual));
-	      pedwarn (location, 0,
-		       "comparison of distinct pointer types lacks a cast");
+              pedwarn (location, OPT_Wcompare_distinct_pointer_types,
+                       "comparison of distinct pointer types lacks a cast");
 	    }
 	}
       else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3380ed8bd6f99de5255b6959807ecf919a491fd2..01aa9efebce5a669299f83c42dbb9fb3e5a0d0b0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -345,6 +345,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wcast-align  -Wcast-align=strict  -Wcast-function-type  -Wcast-qual
 -Wchar-subscripts
 -Wclobbered  -Wcomment
+-Wcompare-distinct-pointer-types
 -Wno-complain-wrong-lang
 -Wconversion  -Wno-coverage-mismatch  -Wno-cpp
 -Wdangling-else  -Wdangling-pointer  -Wdangling-pointer=@var{n}
@@ -9106,6 +9107,11 @@ The latter front end diagnoses
 @samp{f951: Warning: command-line option '-fno-rtti' is valid for C++/D/ObjC++ but not for Fortran},
 which may be disabled with @option{-Wno-complain-wrong-lang}.
 
+@opindex Wcompare-distinct-pointer-types
+@item -Wcompare-distinct-pointer-types @r{(C and Objective-C only)}
+Warn if pointers of distinct types are compared without a cast.  This
+warning is enabled by default.
+
 @opindex Wconversion
 @opindex Wno-conversion
 @item -Wconversion
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f3b06577d52f4acd06d4cf9e97075898e2b8a47
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-1.c
@@ -0,0 +1,34 @@
+/* { dg-do compile }
+   { dg-options "-O0" }
+   This testcase checks that warn_compare_distinct_pointer_types is enabled by
+   default.  */
+
+typedef int __u32;
+
+struct xdp_md
+{
+  char *data;
+  char *data_meta;
+};
+
+int xdp_context (struct xdp_md *xdp)
+{
+  void *data = (void *)(long)xdp->data;
+  __u32 *metadata = (void *)(long)xdp->data_meta;
+  __u32 ret;
+
+  if (metadata + 1 > data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 1;
+  if (metadata + 1 >= data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 2;
+  if (metadata + 1 < data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 3;
+  if (metadata + 1 <= data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 4;
+  if (metadata + 1 == data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 5;
+  if (metadata + 1 != data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 5;
+
+  return 1;
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..6876adf3aab1090a9a90e454faecbd47609f341a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-2.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-Wcompare-distinct-pointer-types" } */
+
+typedef int __u32;
+
+struct xdp_md
+{
+  char *data;
+  char *data_meta;
+};
+
+int xdp_context (struct xdp_md *xdp)
+{
+  void *data = (void *)(long)xdp->data;
+  __u32 *metadata = (void *)(long)xdp->data_meta;
+  __u32 ret;
+
+  if (metadata + 1 > data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 1;
+  if (metadata + 1 >= data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 2;
+  if (metadata + 1 < data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 3;
+  if (metadata + 1 <= data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 4;
+  if (metadata + 1 == data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 5;
+  if (metadata + 1 != data) /* { dg-warning "comparison of distinct pointer types" } */
+    return 5;
+
+  return 1;
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c b/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..73c9b251824d4b8e819ea2895018a91333f3c0eb
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr106537-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wno-compare-distinct-pointer-types" } */
+
+typedef int __u32;
+
+struct xdp_md
+{
+  char *data;
+  char *data_meta;
+};
+
+int xdp_context (struct xdp_md *xdp)
+{
+  void *data = (void *)(long)xdp->data;
+  __u32 *metadata = (void *)(long)xdp->data_meta;
+  __u32 ret;
+
+  if (metadata + 1 > data) /* There shouldn't be a warning here.  */
+    return 1;
+  if (metadata + 1 >= data) /* There shouldn't be a warning here. */
+    return 2;
+  if (metadata + 1 < data) /* There shouldn't be a warning here.  */
+    return 3;
+  if (metadata + 1 <= data) /* There shouldn't be a warning here.  */
+    return 4;
+  if (metadata + 1 == data) /* There shouldn't be a warning here.  */
+    return 5;
+  if (metadata + 1 != data) /* There shouldn't be a warning here.  */
+    return 5;
+
+  return 1;
+}