From 4b97a583152e3535b8dd07ebeb80b16bf57f5c7b Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 19 Jul 2017 11:06:13 -0400
Subject: [PATCH 1/6] Add param-type-mismatch.c/C testcases as a baseline

I have various patch kits under development that improve
how the C and C++ frontends handle mismatched types of
params at callsites.

For example, given:

  extern int callee_1 (int one, const char *two, float three);

  int test_1 (int first, int second, float third)
  {
    return callee_1 (first, second, third);
  }

the C++ FE currently reports:

  error: invalid conversion from 'int' to 'const char*' [-fpermissive]
   return callee_1 (first, second, third);
                                        ^
  note:   initializing argument 2 of 'int callee_1(int, const char*, float)'
   extern int callee_1 (int one, const char *two, float three);
              ^~~~~~~~

when it ought to underline the pertinent parts of the code:

  error: invalid conversion from 'int' to 'const char*' [-fpermissive]
   return callee_1 (first, second, third);
                           ^~~~~~
  note:   initializing argument 2 of 'int callee_1(int, const char*, float)'
   extern int callee_1 (int one, const char *two, float three);
                                 ^~~~~~~~~~~~~~~

The C FE currently does better, underlining the pertinent argument at
the callsite (due to the "vec<location_t> arg_loc" passed around
when the call is created); but, like the C++ frontend, it doesn't
underline the pertinent parameter at the decl of the callee.

This patch adds a pair of test cases to exercise various cases of
this in the C and C++ frontends, to establish a baseline for how
we currently handle these; the "TODO" comments in the test cases
note the aspects where we could do better (some of which are fixed
by this kit).

Adds 13 PASS results to gcc.sum.
Adds 96 PASS results to g++.sum.

[I posted an earlier version of this as:
  https://gcc.gnu.org/ml/gcc-patches/2017-07/msg01454.html ;
this version adds a little more test coverage for C++]

gcc/testsuite/ChangeLog:
	* g++.dg/diagnostic/param-type-mismatch.C: New test acse.
	* gcc.dg/param-type-mismatch.c: New test case.
---
 .../g++.dg/diagnostic/param-type-mismatch.C        | 179 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/param-type-mismatch.c         |  63 ++++++++
 2 files changed, 242 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
 create mode 100644 gcc/testsuite/gcc.dg/param-type-mismatch.c

diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
new file mode 100644
index 0000000..b8833ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
@@ -0,0 +1,179 @@
+// { dg-options "-fdiagnostics-show-caret" }
+
+/* A collection of calls where argument 2 is of the wrong type.
+
+   TODO: we should put the caret and underline for the diagnostic
+   at the second argument, rather than the close paren.
+
+   TODO: we should highlight the second parameter of the callee, rather
+   than its name.  */
+
+/* decl, with argname.  */
+
+extern int callee_1 (int one, const char *two, float three); // { dg-line callee_1 }
+
+int test_1 (int first, int second, float third)
+{
+  return callee_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_1 (first, second, third);
+                                        ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_1 }
+  /* { dg-begin-multiline-output "" }
+ extern int callee_1 (int one, const char *two, float three);
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* decl, without argname.  */
+
+extern int callee_2 (int, const char *, float); // { dg-line callee_2 }
+
+int test_2 (int first, int second, float third)
+{
+  return callee_2 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_2 (first, second, third);
+                                        ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_2 }
+  /* { dg-begin-multiline-output "" }
+ extern int callee_2 (int, const char *, float);
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* defn, with argname.  */
+
+static int callee_3 (int one, const char *two, float three) // { dg-line callee_3 }
+{
+  return callee_2 (one, two, three);
+}
+
+int test_3 (int first, int second, float third)
+{
+  return callee_3 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return callee_3 (first, second, third);
+                                        ^
+     { dg-end-multiline-output "" } */
+  // { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_3 }
+  /* { dg-begin-multiline-output "" }
+ static int callee_3 (int one, const char *two, float three)
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* static member, with argname.  */
+
+struct s4 { static int member_1 (int one, const char *two, float three); };
+
+int test_4 (int first, int second, float third)
+{
+  return s4::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return s4::member_1 (first, second, third);
+                                            ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s4 { static int member_1 (int one, const char *two, float three); };
+                        ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* non-static member, with argname.  */
+
+struct s5 { int member_1 (int one, const char *two, float three); };
+
+int test_5 (int first, int second, float third)
+{
+  s5 inst;
+  return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return inst.member_1 (first, second, third);
+                                             ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s5 { int member_1 (int one, const char *two, float three); };
+                 ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* non-static member, with argname, via a ptr.  */
+
+struct s6 { int member_1 (int one, const char *two, float three); };
+
+int test_6 (int first, int second, float third, s6 *ptr)
+{
+  return ptr->member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return ptr->member_1 (first, second, third);
+                                             ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s6 { int member_1 (int one, const char *two, float three); };
+                 ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template function.  */
+
+template <typename T>
+int test_7 (int one, T two, float three);
+
+int test_7 (int first, int second, float third)
+{
+  return test_7 <const char *> (first, second, third); // { dg-error "no matching function" }
+  /* { dg-begin-multiline-output "" }
+   return test_7 <const char *> (first, second, third);
+                                                     ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+   return test_7 <const char *> (first, second, third);
+                                                     ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ int test_7 (int one, T two, float three);
+     ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, static function.  */
+
+template <typename T>
+struct s8 { static int member_1 (int one, T two, float three); };
+
+int test_8 (int first, int second, float third)
+{
+  return s8 <const char *>::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return s8 <const char *>::member_1 (first, second, third);
+                                                           ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s8 { static int member_1 (int one, T two, float three); };
+                        ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, non-static function.  */
+
+template <typename T>
+struct s9 { int member_1 (int one, T two, float three); };
+
+int test_9 (int first, int second, float third)
+{
+  s9 <const char *> inst;
+  return inst.member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return inst.member_1 (first, second, third);
+                                             ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s9 { int member_1 (int one, T two, float three); };
+                 ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+// TODO: template callsite
diff --git a/gcc/testsuite/gcc.dg/param-type-mismatch.c b/gcc/testsuite/gcc.dg/param-type-mismatch.c
new file mode 100644
index 0000000..70ea0bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/param-type-mismatch.c
@@ -0,0 +1,63 @@
+/* { dg-options "-fdiagnostics-show-caret" }  */
+
+/* A collection of calls where argument 2 is of the wrong type.
+
+   TODO: we should highlight the second parameter of the callee, rather
+   than its name.  */
+
+/* decl, with argname.  */
+
+extern int callee_1 (int one, const char *two, float three); /* { dg-line callee_1 } */
+
+int test_1 (int first, int second, float third)
+{
+  return callee_1 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_1' makes pointer from integer without a cast" }  */
+  /* { dg-begin-multiline-output "" }
+   return callee_1 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+  /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_1 } */
+  /* { dg-begin-multiline-output "" }
+ extern int callee_1 (int one, const char *two, float three);
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* decl, without argname.  */
+
+extern int callee_2 (int, const char *, float); /* { dg-line callee_2 } */
+
+int test_2 (int first, int second, float third)
+{
+  return callee_2 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_2' makes pointer from integer without a cast" } */
+  /* { dg-begin-multiline-output "" }
+   return callee_2 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+  /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_2 } */
+  /* { dg-begin-multiline-output "" }
+ extern int callee_2 (int, const char *, float);
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* defn, with argname.  */
+
+static int callee_3 (int one, const char *two, float three) /* { dg-line callee_3 } */
+{
+  return callee_2 (one, two, three);
+}
+
+int test_3 (int first, int second, float third)
+{
+  return callee_3 (first, second, third); // { dg-warning "passing argument 2 of 'callee_3' makes pointer from integer without a cast" }
+  /* { dg-begin-multiline-output "" }
+   return callee_3 (first, second, third);
+                           ^~~~~~
+     { dg-end-multiline-output "" } */
+  /* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_3 } */
+  /* { dg-begin-multiline-output "" }
+ static int callee_3 (int one, const char *two, float three)
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
-- 
1.8.5.3

