Avoid double substitution with complete explicit template arguments.
authorJason Merrill <jason@redhat.com>
Tue, 13 Nov 2018 04:47:20 +0000 (23:47 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 13 Nov 2018 04:47:20 +0000 (23:47 -0500)
Previously, when we got a function template with explicit arguments for all
of the template parameters, we still did "deduction", which of course
couldn't deduce anything, but did other deduction-time checking of
non-dependent conversions and such.  This broke down with the unevaluated
lambdas patch (to follow): substituting into the lambda multiple times, once
to get the function type for deduction and then again to generate the actual
decl, doesn't work, since different substitutions of a lambda produce
different types.  I believe that skipping the initial substitution when we
have all the arguments is still conformant, and produces better diagnostics
for some testcases.

* pt.c (fn_type_unification): If we have a full set of explicit
arguments, go straight to substitution.

From-SVN: r266055

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/decltype48.C
gcc/testsuite/g++.dg/cpp0x/diag1.C
gcc/testsuite/g++.dg/cpp0x/error4.C
gcc/testsuite/g++.dg/cpp0x/pr77655.C
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C

index 79c162c75b05e38c904157753f99c5a17b8a94bb..5cd147114a0e623d5b28709da3b1fd8e783c7af7 100644 (file)
@@ -1,5 +1,8 @@
 2018-11-12  Jason Merrill  <jason@redhat.com>
 
+       * pt.c (fn_type_unification): If we have a full set of explicit
+       arguments, go straight to substitution.
+
        * decl2.c (min_vis_expr_r, expr_visibility): New.
        (min_vis_r): Call expr_visibility.
        (constrain_visibility_for_template): Likewise.
index 0c33c8e1527085ed300d1c259f5820ca43e8d597..f948aef37768d1ecd6d9ae1693dfb0cb47459b2d 100644 (file)
@@ -19800,6 +19800,11 @@ fn_type_unification (tree fn,
   tsubst_flags_t complain = (explain_p ? tf_warning_or_error : tf_none);
   bool ok;
   static int deduction_depth;
+  /* type_unification_real will pass back any access checks from default
+     template argument substitution.  */
+  vec<deferred_access_check, va_gc> *checks = NULL;
+  /* We don't have all the template args yet.  */
+  bool incomplete = true;
 
   tree orig_fn = fn;
   if (flag_new_inheriting_ctors)
@@ -19857,7 +19862,7 @@ fn_type_unification (tree fn,
         template results in an invalid type, type deduction fails.  */
       int i, len = TREE_VEC_LENGTH (tparms);
       location_t loc = input_location;
-      bool incomplete = false;
+      incomplete = false;
 
       if (explicit_targs == error_mark_node)
        goto fail;
@@ -19923,33 +19928,52 @@ fn_type_unification (tree fn,
             }
         }
 
-      if (!push_tinst_level (fn, explicit_targs))
+      if (incomplete)
        {
-         excessive_deduction_depth = true;
-         goto fail;
-       }
-      processing_template_decl += incomplete;
-      input_location = DECL_SOURCE_LOCATION (fn);
-      /* Ignore any access checks; we'll see them again in
-        instantiate_template and they might have the wrong
-        access path at this point.  */
-      push_deferring_access_checks (dk_deferred);
-      fntype = tsubst (TREE_TYPE (fn), explicit_targs,
-                      complain | tf_partial | tf_fndecl_type, NULL_TREE);
-      pop_deferring_access_checks ();
-      input_location = loc;
-      processing_template_decl -= incomplete;
-      pop_tinst_level ();
+         if (!push_tinst_level (fn, explicit_targs))
+           {
+             excessive_deduction_depth = true;
+             goto fail;
+           }
+         ++processing_template_decl;
+         input_location = DECL_SOURCE_LOCATION (fn);
+         /* Ignore any access checks; we'll see them again in
+            instantiate_template and they might have the wrong
+            access path at this point.  */
+         push_deferring_access_checks (dk_deferred);
+         tsubst_flags_t ecomplain = complain | tf_partial | tf_fndecl_type;
+         fntype = tsubst (TREE_TYPE (fn), explicit_targs, ecomplain, NULL_TREE);
+         pop_deferring_access_checks ();
+         input_location = loc;
+         --processing_template_decl;
+         pop_tinst_level ();
 
-      if (fntype == error_mark_node)
-       goto fail;
+         if (fntype == error_mark_node)
+           goto fail;
+       }
 
       /* Place the explicitly specified arguments in TARGS.  */
       explicit_targs = INNERMOST_TEMPLATE_ARGS (explicit_targs);
       for (i = NUM_TMPL_ARGS (explicit_targs); i--;)
        TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (explicit_targs, i);
+      if (!incomplete && CHECKING_P
+         && !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
+       SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT
+         (targs, NUM_TMPL_ARGS (explicit_targs));
+    }
+
+  if (return_type && strict != DEDUCE_CALL)
+    {
+      tree *new_args = XALLOCAVEC (tree, nargs + 1);
+      new_args[0] = return_type;
+      memcpy (new_args + 1, args, nargs * sizeof (tree));
+      args = new_args;
+      ++nargs;
     }
 
+  if (!incomplete)
+    goto deduced;
+
   /* Never do unification on the 'this' parameter.  */
   parms = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (fntype));
 
@@ -19963,14 +19987,7 @@ fn_type_unification (tree fn,
     }
   else if (return_type)
     {
-      tree *new_args;
-
       parms = tree_cons (NULL_TREE, TREE_TYPE (fntype), parms);
-      new_args = XALLOCAVEC (tree, nargs + 1);
-      new_args[0] = return_type;
-      memcpy (new_args + 1, args, nargs * sizeof (tree));
-      args = new_args;
-      ++nargs;
     }
 
   /* We allow incomplete unification without an error message here
@@ -19988,11 +20005,6 @@ fn_type_unification (tree fn,
       goto fail;
     }
 
-  /* type_unification_real will pass back any access checks from default
-     template argument substitution.  */
-  vec<deferred_access_check, va_gc> *checks;
-  checks = NULL;
-
   ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
                               full_targs, parms, args, nargs, /*subr=*/0,
                               strict, &checks, explain_p);
@@ -20035,6 +20047,7 @@ fn_type_unification (tree fn,
                                       convs, explain_p))
     goto fail;
 
+ deduced:
   /* All is well so far.  Now, check:
 
      [temp.deduct]
index 39fc4ebf5550887d31c6d256228c2e099da038fe..7f5005b915cd0faadfd1e8726912d0ef7b96a121 100644 (file)
@@ -6,7 +6,7 @@ template<typename T> struct baz { };
 template<typename T> T bar();
 
 template<typename T, typename ... U>
-baz<decltype(bar<Int>(bar<U>() ...))> // { dg-error "no match" }
+baz<decltype(bar<Int>(bar<U>() ...))> // { dg-error "" }
 foo();
 
 int main()
index 9bf7cfe5c8f921f47134621e7fc6768ef9779a49..1f8c4a4482169cb37dc9cbd82baee554dd9c4be3 100644 (file)
@@ -23,7 +23,7 @@ struct TypeC
   //   TypeC::fn()
   // we don't want to see the template header, return type, or parameter bindings
   // for TypeB::fn.
-  template <int N> auto fn() -> decltype(b.fn<N>()); // { dg-bogus "typename|with" }
+  template <int N> auto fn() -> decltype(b.fn<N>()); // { dg-bogus "typename" }
 };
 
 int main()
index bd73b2a766cad4e22a96536d06d1e7102b638dd3..1f365b7a10aba1bb3058858067cd304b4be5e01e 100644 (file)
@@ -12,7 +12,7 @@ struct S {
   template<typename U>
     static decltype(*declval<U>()) get(...); // { dg-error "operator*" }
 
-  typedef decltype(get<T>(declval<T>())) type; // { dg-error "no match" }
+  typedef decltype(get<T>(declval<T>())) type; // { dg-error "" }
 };
 
 struct X { };
index ab2e942cbb8f7a189fee91020bda4f81e5f2d626..8b4ffa66ea608d726a500c9ac8049986fad0ca3e 100644 (file)
@@ -3,7 +3,7 @@
 
 template <class F> void g(F);
 template <class... A>
-auto h(A &&... a) -> decltype(g(0, g<decltype(a)>(a)...)) {  // { dg-error "no matching" }
+auto h(A &&... a) -> decltype(g(0, g<decltype(a)>(a)...)) {  // { dg-error "" }
   h([] {});  // { dg-error "no matching" }
 }
 
index f74f8d39e26f7e4616ad89346319d10f5eb7a900..b19655d649614d74797a4bd3360fd6beb5312316 100644 (file)
@@ -134,21 +134,17 @@ int test_7 (int one, T two, float three); // { dg-line test_7_decl }
 int test_7 (int first, const char *second, float third)
 {
   return test_7 <const char **> (first, second, third); // { dg-line test_7_usage }
-  // { dg-error "no matching function" "" { target *-*-* } test_7_usage }
+  // { dg-message "cannot convert 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } test_7_usage }
   /* { dg-begin-multiline-output "" }
    return test_7 <const char **> (first, second, third);
-                                                      ^
+                                         ^~~~~~
+                                         |
+                                         const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'template<class T> int test_7\\(int, T, float\\)'" "" { target *-*-* } test_7_decl }
+  // { dg-message "initializing argument 2 of 'int test_7\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl }
   /* { dg-begin-multiline-output "" }
  int test_7 (int one, T two, float three);
-     ^~~~~~
-     { dg-end-multiline-output "" } */
-  // { dg-message "template argument deduction/substitution failed:" "" { target *-*-* } test_7_decl }
-  // { dg-message "cannot convert 'second' \\(type 'const char\\*'\\) to type 'const char\\*\\*'" "" { target *-*-* } test_7_usage }
-  /* { dg-begin-multiline-output "" }
-   return test_7 <const char **> (first, second, third);
-                                         ^~~~~~
+                      ~~^~~
      { dg-end-multiline-output "" } */
 }
 
index 50bbd4ae94eab0dce41e9940b6652e18d99b21e8..cb5c3602a66aaa2d7f29d1c004b6d314db27d201 100644 (file)
@@ -130,18 +130,16 @@ 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 "" } */
+  return test_7 <const char *> (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
   /* { dg-begin-multiline-output "" }
    return test_7 <const char *> (first, second, third);
                                         ^~~~~~
+                                        |
+                                        int
      { dg-end-multiline-output "" } */
   /* { dg-begin-multiline-output "" }
  int test_7 (int one, T two, float three);
-     ^~~~~~
+                      ~~^~~
      { dg-end-multiline-output "" } */
 }