public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102
@ 2021-10-08 20:19 Nick Huang
  2021-10-14 11:04 ` Nick Huang
  0 siblings, 1 reply; 6+ messages in thread
From: Nick Huang @ 2021-10-08 20:19 UTC (permalink / raw)
  To: Gcc-patches, Jason Merrill

First of all, I am sorry for my late response as I missed your email.
I need to update my filter setup of gmail after switching from hotmail.

>I think WILDCARD_TYPE_P is what you want, except...
I will try this one.

>Your patch rejects that testcase even without the specialization on
>int[], which no other compiler I'm aware of does;

Honestly I now realize this is a wakeup call for me as I have been
trying to revert PR92010 approach for months as I at that time favor
the early syntax-checking approach which is considered efficient. Now
your testcase reveals me a realist practice that almost all compilers
tolerate this seemingly user's definition error because:
a) It actually follows the principle that template without instantiation
might not give error.
b) "const T" and "T" maybe turn out to be the same after instantiation
as function parameter.
So, I guess this is the real practical approach for most compilers to
rebuild function signature from declaration only when instantiation.
My approach stucks when GCC search declaration for definition because
"T" and "const T" are two different CANONICAL types. So, I now guess
that is why declarator deliberately drops cv-qualifers to tolerate your
testcase.

>You seem to have missed my September 28 mail that argued for fixing the
>bug in determine_specialization that was preventing the 92010 fix from
>handling these cases.

I did try to see this approach, but I was stuck in a sidelined issue of
PR102624 which relates to lambda-in-unevaluated-context. The point is
that I thought PR92010 starts to satisfy this pt.c:tsubst_default_argument:
gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, parmtype));

But I think after introduction of lambda in unevaluated context, this may
not be correct assertion. I could be wrong on this. However, i.e.

template <class T>
void spam(decltype([]{})* ptr=nullptr)
{ }
void foo(){
  spam<int>();
}

When rebuilding lambda type from declaration, it is always a unique
different type. So, that is the reason I thought this rebuild function
type approach is imperfect. In other words,  it is no good to rebuild
function type to satisfy this may-not-be-correct-assertion,

Anyway, I now think PR92010 is practically a good approach and I will
start testing your patch.

Best regards,

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

* Re: [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102
  2021-10-08 20:19 [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102 Nick Huang
@ 2021-10-14 11:04 ` Nick Huang
  2021-10-15 21:00   ` [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102 Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Nick Huang @ 2021-10-14 11:04 UTC (permalink / raw)
  To: Gcc-patches, Jason Merrill

hi Jason,

IMHO, I think your patch probably finally solved this long-standing Core
1001 issue. Of course it is not up to me to say so. I just want to point out
that it even solves the following case, even though it is more or less
expected if concept and lambda all work expectedly.

template<class T>
concept IsLambdaAry3=__is_same(T, decltype(+[]{})[3]);
template<IsLambdaAry3 T>
void bar(const T){}
template<>
void bar<decltype(+[]{})[3]>(const decltype(+[]{})[3]){}

B.Regards,

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

* Re: [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102
  2021-10-14 11:04 ` Nick Huang
@ 2021-10-15 21:00   ` Jason Merrill
  0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2021-10-15 21:00 UTC (permalink / raw)
  To: Nick Huang, Gcc-patches

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

On 10/14/21 07:04, Nick Huang wrote:
> IMHO, I think your patch probably finally solved this long-standing Core
> 1001 issue. Of course it is not up to me to say so. I just want to point out
> that it even solves the following case, even though it is more or less
> expected if concept and lambda all work expectedly.
> 
> template<class T>
> concept IsLambdaAry3=__is_same(T, decltype(+[]{})[3]);
> template<IsLambdaAry3 T>
> void bar(const T){}
> template<>
> void bar<decltype(+[]{})[3]>(const decltype(+[]{})[3]){}

Sounds good.  Here's what I'm applying:

[-- Attachment #2: 0001-c-array-cv-quals-and-template-specialization-PR10140.patch --]
[-- Type: text/x-patch, Size: 9484 bytes --]

From 79802c5dcc043a515f429bb2bec7573b8537c32a Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Tue, 28 Sep 2021 10:02:04 -0400
Subject: [PATCH] c++: array cv-quals and template specialization [PR101402]
To: gcc-patches@gcc.gnu.org

PRs 101402, 102033, etc. demonstrated that the fix for PR92010 wasn't
handling all cases of the CWG1001/1322 issue with parameter type qual
stripping and arrays with templates.  The problem turned out to be in
determine_specialization, which did an extra substitution without the 92010
fix and then complained that the result didn't match.

But just removing that wrong/redundant code meant that we were accepting
specializations with different numbers of parameters, because the code in
fn_type_unification that compares types in this case wasn't checking for
length mismatch.

After fixing that, I realized that fn_type_unification couldn't tell the
difference between variadic and non-variadic function types, because the
args array doesn't include the terminal void we use to indicate non-variadic
function type.  So I added it, and made the necessary adjustments.

Thanks to qingzhe "nick" huang <nickhuang99@hotmail.com> for the patch that
led me to dig more into this, and the extensive testcases.

	PR c++/51851
	PR c++/101402
	PR c++/102033
	PR c++/102034
	PR c++/102039
	PR c++/102044

gcc/cp/ChangeLog:

	* pt.c (determine_specialization): Remove redundant code.
	(fn_type_unification): Check for mismatched length.
	(type_unification_real): Ignore terminal void.
	(get_bindings): Don't stop at void_list_node.
	* class.c (resolve_address_of_overloaded_function): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/template/fnspec2.C: New test.
	* g++.dg/template/parm-cv1.C: New test.
	* g++.dg/template/parm-cv2.C: New test.
	* g++.dg/template/parm-cv3.C: New test.
---
 gcc/cp/class.c                           |   2 +-
 gcc/cp/pt.c                              |  30 +++--
 gcc/testsuite/g++.dg/template/fnspec2.C  |   9 ++
 gcc/testsuite/g++.dg/template/parm-cv1.C |  15 +++
 gcc/testsuite/g++.dg/template/parm-cv2.C |  23 ++++
 gcc/testsuite/g++.dg/template/parm-cv3.C | 142 +++++++++++++++++++++++
 6 files changed, 204 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/fnspec2.C
 create mode 100644 gcc/testsuite/g++.dg/template/parm-cv1.C
 create mode 100644 gcc/testsuite/g++.dg/template/parm-cv2.C
 create mode 100644 gcc/testsuite/g++.dg/template/parm-cv3.C

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 59611627d18..f16e50b9de9 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -8382,7 +8382,7 @@ resolve_address_of_overloaded_function (tree target_type,
       nargs = list_length (target_arg_types);
       args = XALLOCAVEC (tree, nargs);
       for (arg = target_arg_types, ia = 0;
-	   arg != NULL_TREE && arg != void_list_node;
+	   arg != NULL_TREE;
 	   arg = TREE_CHAIN (arg), ++ia)
 	args[ia] = TREE_VALUE (arg);
       nargs = ia;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 009fe6db573..287cf4ce9d0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2230,7 +2230,6 @@ determine_specialization (tree template_id,
 	{
 	  tree decl_arg_types;
 	  tree fn_arg_types;
-	  tree insttype;
 
 	  /* In case of explicit specialization, we need to check if
 	     the number of template headers appearing in the specialization
@@ -2356,20 +2355,6 @@ determine_specialization (tree template_id,
 	       template argument.  */
 	    continue;
 
-          /* Remove, from the set of candidates, all those functions
-             whose constraints are not satisfied. */
-          if (flag_concepts && !constraints_satisfied_p (fn, targs))
-            continue;
-
-          // Then, try to form the new function type.
-	  insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE);
-	  if (insttype == error_mark_node)
-	    continue;
-	  fn_arg_types
-	    = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (insttype));
-	  if (!compparms (fn_arg_types, decl_arg_types))
-	    continue;
-
 	  /* Save this template, and the arguments deduced.  */
 	  templates = tree_cons (targs, fn, templates);
 	}
@@ -21862,6 +21847,15 @@ fn_type_unification (tree fn,
 				 TREE_VALUE (sarg));
 	    goto fail;
 	  }
+      if ((i < nargs || sarg)
+	  /* add_candidates uses DEDUCE_EXACT for x.operator foo(), but args
+	     doesn't contain the trailing void, and conv fns are always ().  */
+	  && !DECL_CONV_FN_P (decl))
+	{
+	  unsigned nsargs = i + list_length (sarg);
+	  unify_arity (explain_p, nargs, nsargs);
+	  goto fail;
+	}
     }
 
   /* After doing deduction with the inherited constructor, actually return an
@@ -22385,6 +22379,10 @@ type_unification_real (tree tparms,
   args = xargs;
   nargs = xnargs;
 
+  /* Only fn_type_unification cares about terminal void.  */
+  if (nargs && args[nargs-1] == void_type_node)
+    --nargs;
+
   ia = 0;
   while (parms && parms != void_list_node
 	 && ia < nargs)
@@ -24886,7 +24884,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
   nargs = list_length (decl_arg_types);
   args = XALLOCAVEC (tree, nargs);
   for (arg = decl_arg_types, ix = 0;
-       arg != NULL_TREE && arg != void_list_node;
+       arg != NULL_TREE;
        arg = TREE_CHAIN (arg), ++ix)
     args[ix] = TREE_VALUE (arg);
 
diff --git a/gcc/testsuite/g++.dg/template/fnspec2.C b/gcc/testsuite/g++.dg/template/fnspec2.C
new file mode 100644
index 00000000000..7a4b1012d89
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fnspec2.C
@@ -0,0 +1,9 @@
+template <class T>
+void f(T);
+
+template<> void f(int, ...);	// { dg-error "match" }
+
+template <class T>
+void g(T, ...);
+
+template<> void g(int);		// { dg-error "match" }
diff --git a/gcc/testsuite/g++.dg/template/parm-cv1.C b/gcc/testsuite/g++.dg/template/parm-cv1.C
new file mode 100644
index 00000000000..2677992770d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/parm-cv1.C
@@ -0,0 +1,15 @@
+// CWG 1001
+
+template<class T> struct A {
+  typedef T arr[3];
+};
+
+template<class T> void f(const typename A<T>::arr) { } // #1
+
+template void f<int>(const A<int>::arr);
+
+template <class T> struct B {
+  void g(T);
+};
+
+template <class T> void B<T>::g(const T) { } // #2
diff --git a/gcc/testsuite/g++.dg/template/parm-cv2.C b/gcc/testsuite/g++.dg/template/parm-cv2.C
new file mode 100644
index 00000000000..cd40e868017
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/parm-cv2.C
@@ -0,0 +1,23 @@
+// PR c++/51851
+
+template<class T>
+struct A
+{
+  typedef double Point[2];
+  virtual double calculate(const Point point) const = 0;
+};
+
+template<class T>
+struct B : public A<T>
+{
+  virtual double calculate(const typename A<T>::Point point) const
+  {
+    return point[0];
+  }
+};
+
+int main()
+{
+  B<int> b;
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/parm-cv3.C b/gcc/testsuite/g++.dg/template/parm-cv3.C
new file mode 100644
index 00000000000..1b69c3b2a48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/parm-cv3.C
@@ -0,0 +1,142 @@
+// CWG 1001/1322
+
+// PR c++/101402
+// PR c++/102033
+// PR c++/102034
+// PR c++/102039
+// PR c++/102044
+
+namespace test2{
+template <class T>
+void f(const T);
+
+template<>
+void f<int[]>(const int*){}
+}
+
+namespace test3{
+template <class T>
+struct A{
+void f(T);
+};
+
+template<class T>
+void A<T>::f(const T){}
+
+template<>
+void A<int[3]>::f(const int*){}
+}
+
+namespace test4 {
+template<class TA>
+struct A{
+  template<class TB>
+  struct B{
+    typedef TB Arr3[3];
+  };
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template B<TB>::Arr3){}
+template <>
+void f<int, char>(const typename A<int>::B<char>::Arr3){}
+}
+
+namespace test5
+{
+struct A{
+  typedef int Arr3[3];
+};
+
+template<class T>
+void f(const typename T::Arr3){}
+
+template<>
+void f<A>(const int[3]){}
+}
+
+namespace test6
+{
+struct A{
+  typedef int Arr3[3];
+};
+template<class T>
+void f(const typename T::Arr3){}
+template<>
+void f<A>(const int*){}
+}
+
+#if __cpp_alias_templates
+namespace test7
+{
+template<class TA>
+struct A{
+  template<class TB>
+  using Type=TB[3];
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template Type<TB>){}
+template <>
+void f<int, char>(const typename A<int>::template Type<char>){}
+}
+namespace test8
+{
+template<class TA>
+struct A{
+  template<class TB>
+  struct B{
+    using TB_Alias=TB;
+    template<class TC=TB_Alias>
+    struct C{
+      typedef TC Arr3[3];
+    };
+  };
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template B<TB>::template C<>::Arr3){}
+template <>
+void f<int, char>(const typename A<int>::template B<char>::template C<>::Arr3){}
+}
+#endif
+
+#if __cpp_decltype
+namespace test0
+{
+template <class T>
+struct A{
+  T arr3[3];
+};
+template <class T>
+void f(const decltype(A<T>::arr3)){}
+template <>
+void f<int>(const int[3]){}
+}
+
+#if __cpp_variable_templates
+namespace test9
+{
+template<unsigned int N, class T>
+void f(const T[N]){}
+
+template<unsigned int N, class T>
+using fPtr=decltype(f<N,T>)*;
+
+template<unsigned int N, class T>
+fPtr<N,T> af[N]={&f<N,T>};
+
+template<unsigned int N, class T>
+void g(const decltype(af<N,T>)){}
+
+template<>
+void g<1,int>(const fPtr<1,int>[1]){}
+}
+#endif
+#endif
+
+#if __cpp_concepts
+template<class T>
+concept IsLambdaAry3=__is_same(T, decltype(+[]{})[3]);
+template<IsLambdaAry3 T>
+void bar(const T){}
+template<>
+void bar<decltype(+[]{})[3]>(const decltype(+[]{})[3]){}
+#endif
-- 
2.27.0


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

* Re: [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102
  2021-10-03 11:14 [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102 Nick Huang
  2021-10-03 20:16 ` Nick Huang
@ 2021-10-07 20:50 ` Jason Merrill
  1 sibling, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2021-10-07 20:50 UTC (permalink / raw)
  To: Nick Huang, Gcc-patches

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

On 10/3/21 07:14, Nick Huang wrote:
> I made a little improvement of my fix by including template
> type parameter to not dropping cv-const because they are similar to dependent
> type which you cannot determine whether they are top-level cv-qualifier or not
> until instantiation.
> 
> +         if (processing_template_decl
> +               && (TREE_CODE (type) == TYPENAME_TYPE
> +                  || TREE_CODE (type) == DECLTYPE_TYPE
> ++                  || TREE_CODE (type) == TEMPLATE_TYPE_PARM  // this is new

I think WILDCARD_TYPE_P is what you want, except...

> 1. It fix your test case of
> template <class T>
> struct A{
>     void f(T);
> };
> template <class T>
> void A<T>::f(const T){ }
> template<>
> void A<int[]>::f(const int*){}
> 
> current GCC mistakenly accepts without considering the gap of missing "const"
> between declaration and out of line definition. clang correctly rejects it.
> (https://www.godbolt.org/z/qb9Tf99eK) and explains the cause nicely.
> My fix also rejects it.

Your patch rejects that testcase even without the specialization on 
int[], which no other compiler I'm aware of does; this is why I think 
this approach is wrong.  I think your approach would make sense for the 
standard to specify, but it doesn't (currently).

You seem to have missed my September 28 mail that argued for fixing the 
bug in determine_specialization that was preventing the 92010 fix from 
handling these cases.  I tried removing the redundant code in 
determine_specialization, but then it turned out that I needed to fix 
the corresponding code in fn_type_unification, as in the patch below. 
This approach does not reject the testcase above, which I think is OK; 
whether the specialization is well-formed depends on which declaration 
we are trying to specialize, and GCC chooses the definition.

Thoughts?

[-- Attachment #2: 0001-c-array-cv-quals-and-template-specialization.patch --]
[-- Type: text/x-patch, Size: 4738 bytes --]

From 8671432aac3444603e00c07d0d5d6cebda7d5da8 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Tue, 28 Sep 2021 10:02:04 -0400
Subject: [PATCH] c++: array cv-quals and template specialization
To: gcc-patches@gcc.gnu.org

gcc/cp/ChangeLog:

	* pt.c (determine_specialization): Remove redundant code.
	(fn_type_unification): Check for mismatched length.
	(type_unification_real): Ignore terminal void.
	(get_bindings): Don't stop at void_list_node.
	* class.c (resolve_address_of_overloaded_function): Likewise.

gcc/testsuite/ChangeLog:

	* g++.dg/parse/pr101402.C: No errors.
	* g++.dg/template/fnspec2.C: New test.
---
 gcc/cp/class.c                          |  2 +-
 gcc/cp/pt.c                             | 30 ++++++++++++-------------
 gcc/testsuite/g++.dg/parse/pr101402.C   |  4 ++--
 gcc/testsuite/g++.dg/template/fnspec2.C |  9 ++++++++
 4 files changed, 26 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/fnspec2.C

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 59611627d18..f16e50b9de9 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -8382,7 +8382,7 @@ resolve_address_of_overloaded_function (tree target_type,
       nargs = list_length (target_arg_types);
       args = XALLOCAVEC (tree, nargs);
       for (arg = target_arg_types, ia = 0;
-	   arg != NULL_TREE && arg != void_list_node;
+	   arg != NULL_TREE;
 	   arg = TREE_CHAIN (arg), ++ia)
 	args[ia] = TREE_VALUE (arg);
       nargs = ia;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 19e03369ffa..2eb641e0304 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -2230,7 +2230,6 @@ determine_specialization (tree template_id,
 	{
 	  tree decl_arg_types;
 	  tree fn_arg_types;
-	  tree insttype;
 
 	  /* In case of explicit specialization, we need to check if
 	     the number of template headers appearing in the specialization
@@ -2356,20 +2355,6 @@ determine_specialization (tree template_id,
 	       template argument.  */
 	    continue;
 
-          /* Remove, from the set of candidates, all those functions
-             whose constraints are not satisfied. */
-          if (flag_concepts && !constraints_satisfied_p (fn, targs))
-            continue;
-
-          // Then, try to form the new function type.
-	  insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE);
-	  if (insttype == error_mark_node)
-	    continue;
-	  fn_arg_types
-	    = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (insttype));
-	  if (!compparms (fn_arg_types, decl_arg_types))
-	    continue;
-
 	  /* Save this template, and the arguments deduced.  */
 	  templates = tree_cons (targs, fn, templates);
 	}
@@ -21856,6 +21841,15 @@ fn_type_unification (tree fn,
 				 TREE_VALUE (sarg));
 	    goto fail;
 	  }
+      if ((i < nargs || sarg)
+	  /* add_candidates uses DEDUCE_EXACT for x.operator foo(), but args
+	     doesn't contain the trailing void, and conv fns are always ().  */
+	  && !DECL_CONV_FN_P (decl))
+	{
+	  unsigned nsargs = i + list_length (sarg);
+	  unify_arity (explain_p, nargs, nsargs);
+	  goto fail;
+	}
     }
 
   /* After doing deduction with the inherited constructor, actually return an
@@ -22379,6 +22373,10 @@ type_unification_real (tree tparms,
   args = xargs;
   nargs = xnargs;
 
+  /* Only fn_type_unification cares about terminal void.  */
+  if (nargs && args[nargs-1] == void_type_node)
+    --nargs;
+
   ia = 0;
   while (parms && parms != void_list_node
 	 && ia < nargs)
@@ -24880,7 +24878,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
   nargs = list_length (decl_arg_types);
   args = XALLOCAVEC (tree, nargs);
   for (arg = decl_arg_types, ix = 0;
-       arg != NULL_TREE && arg != void_list_node;
+       arg != NULL_TREE;
        arg = TREE_CHAIN (arg), ++ix)
     args[ix] = TREE_VALUE (arg);
 
diff --git a/gcc/testsuite/g++.dg/parse/pr101402.C b/gcc/testsuite/g++.dg/parse/pr101402.C
index 42a9ce3ab78..7cf02da5401 100644
--- a/gcc/testsuite/g++.dg/parse/pr101402.C
+++ b/gcc/testsuite/g++.dg/parse/pr101402.C
@@ -22,8 +22,8 @@ void f(T);
 };
 
 template<class T>
-void A<T>::f(const T){} /* { dg-error "no declaration matches" } */
+void A<T>::f(const T){}
 
 template<>
-void A<int[3]>::f(const int*){} /* { dg-error "does not match any template declaration" } */
+void A<int[3]>::f(const int*){}
 }
diff --git a/gcc/testsuite/g++.dg/template/fnspec2.C b/gcc/testsuite/g++.dg/template/fnspec2.C
new file mode 100644
index 00000000000..7a4b1012d89
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/fnspec2.C
@@ -0,0 +1,9 @@
+template <class T>
+void f(T);
+
+template<> void f(int, ...);	// { dg-error "match" }
+
+template <class T>
+void g(T, ...);
+
+template<> void g(int);		// { dg-error "match" }
-- 
2.27.0


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

* Re: [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102
  2021-10-03 11:14 [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102 Nick Huang
@ 2021-10-03 20:16 ` Nick Huang
  2021-10-07 20:50 ` [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102 Jason Merrill
  1 sibling, 0 replies; 6+ messages in thread
From: Nick Huang @ 2021-10-03 20:16 UTC (permalink / raw)
  To: Gcc-patches, Jason Merrill

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

Here I attach [PATCH-v2].

On Sun, Oct 3, 2021 at 7:14 AM Nick Huang <nickhuang99@gmail.com> wrote:
>
> Hi Jason,
>
> I made a little improvement of my fix by including template
> type parameter to not dropping cv-const because they are similar to dependent
> type which you cannot determine whether they are top-level cv-qualifier or not
> until instantiation.
>
> +         if (processing_template_decl
> +               && (TREE_CODE (type) == TYPENAME_TYPE
> +                  || TREE_CODE (type) == DECLTYPE_TYPE
> ++                  || TREE_CODE (type) == TEMPLATE_TYPE_PARM  // this is new
> +                  )
> +            )
>
> 1. It fix your test case of
> template <class T>
> struct A{
>    void f(T);
> };
> template <class T>
> void A<T>::f(const T){ }
> template<>
> void A<int[]>::f(const int*){}
>
> current GCC mistakenly accepts without considering the gap of missing "const"
> between declaration and out of line definition. clang correctly rejects it.
> (https://www.godbolt.org/z/qb9Tf99eK) and explains the cause nicely.
> My fix also rejects it.
>
> 2. It also fix a more obvious core1001 issue of free function as my previous fix
> only deals with typename/decltype cases.
> template<class T>
> void f(const T){}
> template<>
> void f<int[3]>(const int*){}
>
> Your comment is appreciated.
>
> thank you

[-- Attachment #2: 0001-Fix-core1001-1322-by-preserve-const.patch --]
[-- Type: text/x-patch, Size: 10430 bytes --]

From 0d096262fc708edea825af713526b1ce1e9e689d Mon Sep 17 00:00:00 2001
From: qingzhe huang <nickhuang99@gmail.com>
Date: Sun, 3 Oct 2021 16:00:29 -0400
Subject: [PATCH] Fix core1001/1322 by preserving const
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

These bugs are considered duplicate cases of PR51851 which has been
suspended since 2012, an issue known as "core1001/1322". Considering
this background, it deserves a long comment to explain.

Many people believed the root cause of this family of bugs is related
with the nature of how and when the array type is converted to pointer
type during function signature is calculated. This is true, but we may
need to go into details to understand the exact reason.

There is a pattern for these bugs(PR101402,PR102033,PR102034,PR102039).
In the template function declaration, the function parameter is consisted
of a "const" followed by a typename-type which is actually an array type.
According to standard, function signature is calculated by dropping so-
called "top-level-cv-qualifier". As a result, the templater specialization
complains no matching to declaration can be found because specialization
has const and template function declaration doesn't have const which is
dropped as mentioned. Obviously the template function declaration should
NOT drop the const. But why? Let's review the procedure of standard first.
(https://timsong-cpp.github.io/cppwp/dcl.fct#5.sentence-3)

"After determining the type of each parameter, any parameter of type
“array of T” or of function type T is adjusted to be “pointer to T”. After
producing the list of parameter types, any top-level cv-qualifiers
modifying a parameter type are deleted when forming the function type."

Please note the action of deleting top-level cv-qualifiers happens at last
stage after array type is converted to pointer type. More importantly,
there are two conditions:
a) Each type must be able to be determined.
b) The cv-qualifier must be top-level.
Let's analysis if these two conditions can be met one by one.
1) Keyword "typename" indicates inside template it involves dependent name
(https://timsong-cpp.github.io/cppwp/n4659/temp.res#2) for which the name
lookup can be postponed until template instantiation. Clearly the type of
dependent name cannot be determined without name lookup. Then we can NOT
proceed to next step until concrete template argument type is determined
during specialization.
2) After “array of T” is converted to “pointer to T”, the cv-qualifiers
are no longer top-level! Unfortunately in standard there is no definition
of "top-level". Mr. Dan Saks's articals
(https://www.dansaks.com/articles.shtml)
are tremendous help! Especially this wonderful paper
(https://www.dansaks.com/articles/
2000-02%20Top-Level%20cv-Qualifiers%20in%20Function%20Parameters.pdf)
discusses this topic in details. In one short sentence, the "const" before
array type is NOT top-level-cv-qualifier and should NOT be dropped.

So, understanding the root cause makes the fix very clear: Let's NOT drop
cv-qualifier for typename-type inside template. Leave this task for
template substitution later when template specialization locks template
argument types.

Similarly inside template, "decltype" may also include dependent name and
the best strategy for parser is to preserve all original declaration and
postpone the task till template substitution.

For template type parameter, it is obvious to follow similar strategy to
not drop cv-const and leave it till instantiation.

Here is an interesting observation to share. Originally my fix is trying
to use function "resolve_typename_type" to see if the "typename-type" is
indeed an array type so as to decide whether the const should be dropped.
It works for cases of PR101402,PR102033(with a small fix of function), but
cannot succeed on cases of PR102034,PR102039. Especially PR102039 is
impossible because it depends on template argument. This helps me realize
that parser should not do any work if it cannot be 100% successful. All
can wait.

At last I want to acknowledge other efforts to tackle this core 1001/1322
from PR92010 which is an irreplaceable different approach from this fix
by doing rebuilding template function signature during template
substitution stage.

After all, this fix can only deal with dependent type started with
"typename" or "decltype" or template type parameter  which is not the
case of pr92010.

gcc/cp/ChangeLog:
	PR c++/101402
	PR c++/102033
	PR c++/102034
	PR c++/102039
	PR c++/102044
	* decl.c (grokparms): Excludes typename,decltype and template
	type parameter to drop cv-const.

gcc/testsuite/ChangeLog:
	PR c++/101402
	PR c++/102033
	PR c++/102034
	PR c++/102039
	PR c++/102044
	* g++.dg/parse/pr101402.C: New test.
	* g++.dg/parse/pr102033.C: New test.
	* g++.dg/parse/pr102034.C: New test.
	* g++.dg/parse/pr102039.C: New test.
	* g++.dg/parse/pr102044.C: New test.

Signed-off-by: qingzhe huang <nickhuang99@gmail.com>
---
 gcc/cp/decl.c                         | 16 ++++++++++++-
 gcc/testsuite/g++.dg/parse/pr101402.C | 29 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/parse/pr102033.C | 34 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/parse/pr102034.C | 13 ++++++++++
 gcc/testsuite/g++.dg/parse/pr102039.C | 24 +++++++++++++++++++
 gcc/testsuite/g++.dg/parse/pr102044.C | 32 +++++++++++++++++++++++++
 6 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/parse/pr101402.C
 create mode 100644 gcc/testsuite/g++.dg/parse/pr102033.C
 create mode 100644 gcc/testsuite/g++.dg/parse/pr102034.C
 create mode 100644 gcc/testsuite/g++.dg/parse/pr102039.C
 create mode 100644 gcc/testsuite/g++.dg/parse/pr102044.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 90111e4c786..dac0c50f886 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -13995,7 +13995,21 @@ grokparms (tree parmlist, tree *parms)
 
 	  /* Top-level qualifiers on the parameters are
 	     ignored for function types.  */
-	  type = cp_build_qualified_type (type, 0);
+
+	  int type_quals = 0;
+	  /* Inside template declaration, typename, decltype
+	     and template type parameter indicating dependent
+	     name and cv-qualifier are preserved until template
+	     instantiation.
+	     PR101402/PR102033/PR102034/PR102039/PR102044 */
+	  if (processing_template_decl
+		&& (TREE_CODE (type) == TYPENAME_TYPE
+		   || TREE_CODE (type) == DECLTYPE_TYPE
+		   || TREE_CODE (type) == TEMPLATE_TYPE_PARM
+		   )
+	     )
+	     type_quals = CP_TYPE_CONST_P(type);
+	  type = cp_build_qualified_type (type, type_quals);
 	  if (TREE_CODE (type) == METHOD_TYPE)
 	    {
 	      error ("parameter %qD invalidly declared method type", decl);
diff --git a/gcc/testsuite/g++.dg/parse/pr101402.C b/gcc/testsuite/g++.dg/parse/pr101402.C
new file mode 100644
index 00000000000..42a9ce3ab78
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr101402.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+namespace test1{
+template<class T> struct A {
+     typedef T arr[3];
+};
+template<class T> void f(const typename A<T>::arr) { } 
+template void f<int>(const A<int>::arr);
+}
+
+namespace test2{
+template <class T>
+void f(const T);
+
+template<>
+void f<int[]>(const int*){}
+}
+
+namespace test3{
+template <class T>
+struct A{
+void f(T);
+};
+
+template<class T>
+void A<T>::f(const T){} /* { dg-error "no declaration matches" } */
+
+template<>
+void A<int[3]>::f(const int*){} /* { dg-error "does not match any template declaration" } */
+}
diff --git a/gcc/testsuite/g++.dg/parse/pr102033.C b/gcc/testsuite/g++.dg/parse/pr102033.C
new file mode 100644
index 00000000000..0d5cc17620f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr102033.C
@@ -0,0 +1,34 @@
+/* {dg-do compile } */
+/* {dg-options "-std=c++11" } */
+
+namespace test1
+{
+template<class TA>
+struct A{
+        template<class TB>
+        using Type=TB[3];
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template Type<TB>){}
+template <>
+void f<int, char>(const typename A<int>::template Type<char>){}
+}
+namespace test2
+{
+template<class TA>
+struct A{
+        template<class TB>
+        struct B{
+                using TB_Alias=TB;
+                template<class TC=TB_Alias>
+                struct C{
+                        typedef TC Arr3[3];
+                };
+        };
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template B<TB>::template C<>::Arr3){}
+template <>
+void f<int, char>(const typename A<int>::template B<char>::template C<>::Arr3){}
+}
+
diff --git a/gcc/testsuite/g++.dg/parse/pr102034.C b/gcc/testsuite/g++.dg/parse/pr102034.C
new file mode 100644
index 00000000000..37fdce52912
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr102034.C
@@ -0,0 +1,13 @@
+/*{dg-do compile} */
+template<class TA>
+struct A{
+        template<class TB>
+        struct B{
+        typedef TB Arr3[3];
+        };
+};
+template<class TA, class TB>
+void f(const typename A<TA>::template B<TB>::Arr3){}
+template <>
+void f<int, char>(const typename A<int>::B<char>::Arr3){}
+
diff --git a/gcc/testsuite/g++.dg/parse/pr102039.C b/gcc/testsuite/g++.dg/parse/pr102039.C
new file mode 100644
index 00000000000..25d3e77fd74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr102039.C
@@ -0,0 +1,24 @@
+namespace test1
+{
+struct A{
+        typedef int Arr3[3];
+};
+
+template<class T>
+void f(const typename T::Arr3){}
+
+template<>
+void f<A>(const int[3]){}
+}
+
+namespace test2
+{
+struct A{
+        typedef int Arr3[3];
+};
+template<class T>
+void f(const typename T::Arr3){}
+template<>
+void f<A>(const int*){}
+}
+
diff --git a/gcc/testsuite/g++.dg/parse/pr102044.C b/gcc/testsuite/g++.dg/parse/pr102044.C
new file mode 100644
index 00000000000..bef6a920b47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/pr102044.C
@@ -0,0 +1,32 @@
+/* {dg-do compile } */
+/* {dg-options "-std=c++11" } */
+namespace test1
+{
+template<unsigned int N, class T>
+void f(const T[N]){}
+
+template<unsigned int N, class T>
+using fPtr=decltype(f<N,T>)*;
+
+template<unsigned int N, class T>
+fPtr<N,T> af[N]={&f<N,T>};
+
+template<unsigned int N, class T>
+void g(const decltype(af<N,T>)){}
+
+template<>
+void g<1,int>(const fPtr<1,int>[1]){}
+}
+
+namespace test2
+{
+template <class T>
+struct A{
+T arr3[3];
+};
+template <class T>
+void f(const decltype(A<T>::arr3)){}
+template <>
+void f<int>(const int[3]){}
+}
+
-- 
2.17.1


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

* [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102
@ 2021-10-03 11:14 Nick Huang
  2021-10-03 20:16 ` Nick Huang
  2021-10-07 20:50 ` [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102 Jason Merrill
  0 siblings, 2 replies; 6+ messages in thread
From: Nick Huang @ 2021-10-03 11:14 UTC (permalink / raw)
  To: Gcc-patches, Jason Merrill

Hi Jason,

I made a little improvement of my fix by including template
type parameter to not dropping cv-const because they are similar to dependent
type which you cannot determine whether they are top-level cv-qualifier or not
until instantiation.

+         if (processing_template_decl
+               && (TREE_CODE (type) == TYPENAME_TYPE
+                  || TREE_CODE (type) == DECLTYPE_TYPE
++                  || TREE_CODE (type) == TEMPLATE_TYPE_PARM  // this is new
+                  )
+            )

1. It fix your test case of
template <class T>
struct A{
   void f(T);
};
template <class T>
void A<T>::f(const T){ }
template<>
void A<int[]>::f(const int*){}

current GCC mistakenly accepts without considering the gap of missing "const"
between declaration and out of line definition. clang correctly rejects it.
(https://www.godbolt.org/z/qb9Tf99eK) and explains the cause nicely.
My fix also rejects it.

2. It also fix a more obvious core1001 issue of free function as my previous fix
only deals with typename/decltype cases.
template<class T>
void f(const T){}
template<>
void f<int[3]>(const int*){}

Your comment is appreciated.

thank you

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

end of thread, other threads:[~2021-10-15 21:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-08 20:19 [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102 Nick Huang
2021-10-14 11:04 ` Nick Huang
2021-10-15 21:00   ` [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102 Jason Merrill
  -- strict thread matches above, loose matches on Subject: below --
2021-10-03 11:14 [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402, PR102033, PR102034, PR102039, PR102 Nick Huang
2021-10-03 20:16 ` Nick Huang
2021-10-07 20:50 ` [PATCH] c++: fix cases of core1001/1322 by not dropping cv-qualifier of function parameter of type of typename or decltype[PR101402,PR102033,PR102034,PR102039,PR102 Jason Merrill

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