summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2021-05-26 08:35:31 -0400
committerPatrick Palka <ppalka@redhat.com>2023-06-30 00:03:14 -0400
commitad42219766d0e67bede2c9bd94c98082cde42518 (patch)
treeb08ab0f677cb6fded649214f46ca8b80432fae9e
parentc48f10004ebc60976294488c59c9df828120db32 (diff)
c++: Fix reference NTTP binding to noexcept fn [PR97420]
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)) &f'). 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. PR c++/97420 gcc/cp/ChangeLog: * 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: * g++.dg/cpp0x/noexcept68.C: New test. (cherry picked from commit b4329e3dd6fb7c78948fcf9d2f5b9d873deec284)
-rw-r--r--gcc/cp/cvt.c36
-rw-r--r--gcc/cp/pt.c5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/noexcept68.C8
3 files changed, 23 insertions, 26 deletions
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 0e11f060c53..fe3282f0d8e 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -2072,7 +2072,8 @@ can_convert_tx_safety (tree to, tree from)
&& same_type_p (to, tx_unsafe_fn_variant (from)));
}
-/* Return true iff FROM can convert to TO by dropping noexcept. */
+/* Return true iff FROM can convert to TO by dropping noexcept.
+ This is just a subroutine of of fnptr_conv_p. */
static bool
noexcept_conv_p (tree to, tree from)
@@ -2080,30 +2081,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. */
@@ -2111,7 +2097,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))
@@ -2119,8 +2105,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 1185cdcaab6..448da256250 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6559,7 +6559,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 00000000000..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<int (&)(int)> void A();
+int main() {
+ A<f>();
+}