Re: [PATCH] c++: Fix reference NTTP binding to noexcept fn [PR97420]

2021-05-24 Thread Jason Merrill via Gcc-patches

On 5/21/21 4:35 PM, Patrick Palka wrote:

Here, in C++17 mode, convert_nontype_argument_function is rejecting
binding a non-noexcept function reference template parameter to a
noexcept function (encoded as the template argument '*(int (&) (int)) ').

The first roadblock to making this work is that the argument is wrapped
an an implicit INDIRECT_REF, so we need to unwrap it before calling
strip_fnptr_conv.

The second roadblock is that the NOP_EXPR cast converts from a function
pointer type to a reference type while simultaneously removing the
noexcept qualification, and fnptr_conv_p doesn't consider this cast to
be a function pointer conversion.  This patch fixes this by making
fnptr_conv_p treat REFERENCE_TYPEs and POINTER_TYPEs interchangeably.

Finally, in passing, this patch also simplifies noexcept_conv_p by
removing a bunch of redundant checks already performed by its only
caller fnptr_conv_p.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?



gcc/cp/ChangeLog:

PR c++/97420
* cvt.c (noexcept_conv_p): Remove redundant checks and simplify.


This is fine, but please also add a note to its comment that it's just a 
subroutine of fnptr_conv_p.


OK with that change.


(fnptr_conv_p): Don't call non_reference.  Use INDIRECT_TYPE_P
instead of TYPE_PTR_P.
* pt.c (convert_nontype_argument_function): Look through
implicit INDIRECT_REFs before calling strip_fnptr_conv.

gcc/testsuite/ChangeLog:

PR c++/97420
* g++.dg/cpp0x/noexcept68.C: New test.
---
  gcc/cp/cvt.c| 33 +++--
  gcc/cp/pt.c |  5 +++-
  gcc/testsuite/g++.dg/cpp0x/noexcept68.C |  8 ++
  3 files changed, 21 insertions(+), 25 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept68.C

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 7fa6e8df52b..582d03f61f5 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -2089,30 +2089,15 @@ noexcept_conv_p (tree to, tree from)
if (!flag_noexcept_type)
  return false;
  
-  tree t = non_reference (to);

-  tree f = from;
-  if (TYPE_PTRMEMFUNC_P (t)
-  && TYPE_PTRMEMFUNC_P (f))
-{
-  t = TYPE_PTRMEMFUNC_FN_TYPE (t);
-  f = TYPE_PTRMEMFUNC_FN_TYPE (f);
-}
-  if (TYPE_PTR_P (t)
-  && TYPE_PTR_P (f))
-{
-  t = TREE_TYPE (t);
-  f = TREE_TYPE (f);
-}
-  tree_code code = TREE_CODE (f);
-  if (TREE_CODE (t) != code)
+  if (TREE_CODE (to) != TREE_CODE (from))
  return false;
-  if (code != FUNCTION_TYPE && code != METHOD_TYPE)
+  if (!FUNC_OR_METHOD_TYPE_P (from))
  return false;
-  if (!type_throw_all_p (t)
-  || type_throw_all_p (f))
+  if (!type_throw_all_p (to)
+  || type_throw_all_p (from))
  return false;
-  tree v = build_exception_variant (f, NULL_TREE);
-  return same_type_p (t, v);
+  tree v = build_exception_variant (from, NULL_TREE);
+  return same_type_p (to, v);
  }
  
  /* Return true iff FROM can convert to TO by a function pointer conversion.  */

@@ -2120,7 +2105,7 @@ noexcept_conv_p (tree to, tree from)
  bool
  fnptr_conv_p (tree to, tree from)
  {
-  tree t = non_reference (to);
+  tree t = to;
tree f = from;
if (TYPE_PTRMEMFUNC_P (t)
&& TYPE_PTRMEMFUNC_P (f))
@@ -2128,8 +2113,8 @@ fnptr_conv_p (tree to, tree from)
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
f = TYPE_PTRMEMFUNC_FN_TYPE (f);
  }
-  if (TYPE_PTR_P (t)
-  && TYPE_PTR_P (f))
+  if (INDIRECT_TYPE_P (t)
+  && INDIRECT_TYPE_P (f))
  {
t = TREE_TYPE (t);
f = TREE_TYPE (f);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 99a9ee5ade2..f3fa9c192ad 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6622,7 +6622,10 @@ convert_nontype_argument_function (tree type, tree expr,
if (value_dependent_expression_p (fn))
  goto accept;
  
-  fn_no_ptr = strip_fnptr_conv (fn);

+  fn_no_ptr = fn;
+  if (REFERENCE_REF_P (fn_no_ptr))
+fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
+  fn_no_ptr = strip_fnptr_conv (fn_no_ptr);
if (TREE_CODE (fn_no_ptr) == ADDR_EXPR)
  fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
if (BASELINK_P (fn_no_ptr))
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept68.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept68.C
new file mode 100644
index 000..086899a4a19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept68.C
@@ -0,0 +1,8 @@
+// PR c++/97420
+// { dg-do compile { target c++11 } }
+
+int f(int) noexcept;
+template void A();
+int main() {
+  A();
+}





[PATCH] c++: Fix reference NTTP binding to noexcept fn [PR97420]

2021-05-21 Thread Patrick Palka via Gcc-patches
Here, in C++17 mode, convert_nontype_argument_function is rejecting
binding a non-noexcept function reference template parameter to a
noexcept function (encoded as the template argument '*(int (&) (int)) ').

The first roadblock to making this work is that the argument is wrapped
an an implicit INDIRECT_REF, so we need to unwrap it before calling
strip_fnptr_conv.

The second roadblock is that the NOP_EXPR cast converts from a function
pointer type to a reference type while simultaneously removing the
noexcept qualification, and fnptr_conv_p doesn't consider this cast to
be a function pointer conversion.  This patch fixes this by making
fnptr_conv_p treat REFERENCE_TYPEs and POINTER_TYPEs interchangeably.

Finally, in passing, this patch also simplifies noexcept_conv_p by
removing a bunch of redundant checks already performed by its only
caller fnptr_conv_p.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

gcc/cp/ChangeLog:

PR c++/97420
* cvt.c (noexcept_conv_p): Remove redundant checks and simplify.
(fnptr_conv_p): Don't call non_reference.  Use INDIRECT_TYPE_P
instead of TYPE_PTR_P.
* pt.c (convert_nontype_argument_function): Look through
implicit INDIRECT_REFs before calling strip_fnptr_conv.

gcc/testsuite/ChangeLog:

PR c++/97420
* g++.dg/cpp0x/noexcept68.C: New test.
---
 gcc/cp/cvt.c| 33 +++--
 gcc/cp/pt.c |  5 +++-
 gcc/testsuite/g++.dg/cpp0x/noexcept68.C |  8 ++
 3 files changed, 21 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/noexcept68.C

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 7fa6e8df52b..582d03f61f5 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -2089,30 +2089,15 @@ noexcept_conv_p (tree to, tree from)
   if (!flag_noexcept_type)
 return false;
 
-  tree t = non_reference (to);
-  tree f = from;
-  if (TYPE_PTRMEMFUNC_P (t)
-  && TYPE_PTRMEMFUNC_P (f))
-{
-  t = TYPE_PTRMEMFUNC_FN_TYPE (t);
-  f = TYPE_PTRMEMFUNC_FN_TYPE (f);
-}
-  if (TYPE_PTR_P (t)
-  && TYPE_PTR_P (f))
-{
-  t = TREE_TYPE (t);
-  f = TREE_TYPE (f);
-}
-  tree_code code = TREE_CODE (f);
-  if (TREE_CODE (t) != code)
+  if (TREE_CODE (to) != TREE_CODE (from))
 return false;
-  if (code != FUNCTION_TYPE && code != METHOD_TYPE)
+  if (!FUNC_OR_METHOD_TYPE_P (from))
 return false;
-  if (!type_throw_all_p (t)
-  || type_throw_all_p (f))
+  if (!type_throw_all_p (to)
+  || type_throw_all_p (from))
 return false;
-  tree v = build_exception_variant (f, NULL_TREE);
-  return same_type_p (t, v);
+  tree v = build_exception_variant (from, NULL_TREE);
+  return same_type_p (to, v);
 }
 
 /* Return true iff FROM can convert to TO by a function pointer conversion.  */
@@ -2120,7 +2105,7 @@ noexcept_conv_p (tree to, tree from)
 bool
 fnptr_conv_p (tree to, tree from)
 {
-  tree t = non_reference (to);
+  tree t = to;
   tree f = from;
   if (TYPE_PTRMEMFUNC_P (t)
   && TYPE_PTRMEMFUNC_P (f))
@@ -2128,8 +2113,8 @@ fnptr_conv_p (tree to, tree from)
   t = TYPE_PTRMEMFUNC_FN_TYPE (t);
   f = TYPE_PTRMEMFUNC_FN_TYPE (f);
 }
-  if (TYPE_PTR_P (t)
-  && TYPE_PTR_P (f))
+  if (INDIRECT_TYPE_P (t)
+  && INDIRECT_TYPE_P (f))
 {
   t = TREE_TYPE (t);
   f = TREE_TYPE (f);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 99a9ee5ade2..f3fa9c192ad 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6622,7 +6622,10 @@ convert_nontype_argument_function (tree type, tree expr,
   if (value_dependent_expression_p (fn))
 goto accept;
 
-  fn_no_ptr = strip_fnptr_conv (fn);
+  fn_no_ptr = fn;
+  if (REFERENCE_REF_P (fn_no_ptr))
+fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
+  fn_no_ptr = strip_fnptr_conv (fn_no_ptr);
   if (TREE_CODE (fn_no_ptr) == ADDR_EXPR)
 fn_no_ptr = TREE_OPERAND (fn_no_ptr, 0);
   if (BASELINK_P (fn_no_ptr))
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept68.C 
b/gcc/testsuite/g++.dg/cpp0x/noexcept68.C
new file mode 100644
index 000..086899a4a19
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept68.C
@@ -0,0 +1,8 @@
+// PR c++/97420
+// { dg-do compile { target c++11 } }
+
+int f(int) noexcept;
+template void A();
+int main() {
+  A();
+}
-- 
2.32.0.rc0