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

Amongst other things, this patch kit aims to improve our handling
of mismatched types within function calls.

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

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        | 162 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/param-type-mismatch.c         |  63 ++++++++
 2 files changed, 225 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..864ead1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
@@ -0,0 +1,162 @@
+// { 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 "" } */
+}
+
+/* Template function.  */
+
+template <typename T>
+int test_6 (int one, T two, float three);
+
+int test_6 (int first, int second, float third)
+{
+  return test_6 <const char *> (first, second, third); // { dg-error "no matching function" }
+  /* { dg-begin-multiline-output "" }
+   return test_6 <const char *> (first, second, third);
+                                                     ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+   return test_6 <const char *> (first, second, third);
+                                                     ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ int test_6 (int one, T two, float three);
+     ^~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, static function.  */
+
+template <typename T>
+struct s7 { static int member_1 (int one, T two, float three); };
+
+int test_7 (int first, int second, float third)
+{
+  return s7 <const char *>::member_1 (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
+  /* { dg-begin-multiline-output "" }
+   return s7 <const char *>::member_1 (first, second, third);
+                                                           ^
+     { dg-end-multiline-output "" } */
+  /* { dg-begin-multiline-output "" }
+ struct s7 { static int member_1 (int one, T two, float three); };
+                        ^~~~~~~~
+     { dg-end-multiline-output "" } */
+}
+
+/* Template class, non-static function.  */
+
+template <typename T>
+struct s8 { int member_1 (int one, T two, float three); };
+
+int test_8 (int first, int second, float third)
+{
+  s8 <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 s8 { 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

