This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [RFA] PR c++/37093
- From: Dodji Seketeli <dodji at redhat dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org, paolo dot carlini at oracle dot com
- Date: Mon, 2 Nov 2009 12:38:20 +0100
- Subject: Re: [RFA] PR c++/37093
- References: <20091030225021.GO25276@adjoa.torimasen.com> <4AEC8381.8010108@redhat.com>
Paolo, Jason,
Thanks for your reviews.
On Sat, Oct 31, 2009 at 02:35:45PM -0400, Jason Merrill wrote:
> I agree with Paolo that the test should be split out so it is shared
> between pointers to data and function members. Also, you seem to be
> reinventing STRIP_NOPS.
OK.
> Using %qD assumes that the expression is a decl, which isn't necessarily
> true. And you already printed the expression once, anyway. I think the
> old second line was good:
>
> ! error ("it must be a pointer-to-member of the form `&X::Y'");
OK.
>
> as it tells the user what syntax we're expecting.
>
>> + && TREE_CODE (nop_stripped_expr) != ADDR_EXPR
>> + && TREE_CODE (nop_stripped_expr) != PTRMEM_CST)
>
> Is it really the case that pointer-to-member constants can appear as
> either ADDR_EXPR or PTRMEM_CST?
You are right. pointer to data member constant are always folded into a
PTRMEM_CST by the time we enter convert_nontype_argument.
Pointer to member function are folded later in convert_nontype_argument,
either by the call to fold_non_dependent_expr or later in the
"else if (TYPE_PTRMEMFUNC_P (type))" by the call to instantiate_type.
So I can just drop the ADDR_EXPR test I think.
The updated patch below was tested against trunk and 4.4.
Dodji
commit 491a843dc1472bcf81d03e45b966171a88160c48
Author: Dodji Seketeli <dodji@redhat.com>
Date: Fri Oct 30 23:27:14 2009 +0100
Fix PR c++/37093
gcc/cp/ChangeLog:
PR c++/37093
* pt.c (check_valid_ptrmem_cst_expr): New function.
* (convert_nontype_argument): Use it to output an error for
illegal pointer to member expressions used as template arguments.
gcc/testsuite/ChangeLog:
PR c++/37093
* g++.dg/other/ptrmem10.C: New test.
* g++.dg/other/ptrmem11.C: Likewise.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ace340e..b915bab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -4685,6 +4685,22 @@ convert_nontype_argument_function (tree type, tree expr)
return fn;
}
+/* Subroutine of convert_nontype_argument.
+ Check if EXPR of type TYPE is a valid pointer-to-member constant.
+ Emit an error otherwise. */
+
+static bool
+check_valid_ptrmem_cst_expr (tree type, tree expr)
+{
+ STRIP_NOPS (expr);
+ if (expr && (null_ptr_cst_p (expr) || TREE_CODE (expr) == PTRMEM_CST))
+ return true;
+ error ("%qE is not a valid template argument for type %qT",
+ expr, type);
+ error ("it must be a pointer-to-member of the form `&X::Y'");
+ return false;
+}
+
/* Attempt to convert the non-type template parameter EXPR to the
indicated TYPE. If the conversion is successful, return the
converted value. If the conversion is unsuccessful, return
@@ -4984,6 +5000,11 @@ convert_nontype_argument (tree type, tree expr)
if (expr == error_mark_node)
return error_mark_node;
+ /* [temp.arg.nontype] bullet 1 says the pointer to member
+ expression must be a pointer-to-member constant. */
+ if (!check_valid_ptrmem_cst_expr (type, expr))
+ return NULL_TREE;
+
/* There is no way to disable standard conversions in
resolve_address_of_overloaded_function (called by
instantiate_type). It is possible that the call succeeded by
@@ -5010,6 +5031,11 @@ convert_nontype_argument (tree type, tree expr)
qualification conversions (_conv.qual_) are applied. */
else if (TYPE_PTRMEM_P (type))
{
+ /* [temp.arg.nontype] bullet 1 says the pointer to member
+ expression must be a pointer-to-member constant. */
+ if (!check_valid_ptrmem_cst_expr (type, expr))
+ return NULL_TREE;
+
expr = perform_qualification_conversions (type, expr);
if (expr == error_mark_node)
return expr;
diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C
new file mode 100644
index 0000000..4b8c40a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/ptrmem10.C
@@ -0,0 +1,29 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/37093
+
+template <class C, void (C::*M) ()>
+static
+void foo(void *obj)
+{
+ C *p = static_cast<C*>(obj);
+ (p->*M)();
+}
+
+template <class C>
+static void
+bar(C *c, void (C::*m) ())
+{
+ foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun)" }
+}
+
+struct S
+{
+ void baz () {}
+};
+
+int
+main ()
+{
+ S a;
+ bar(&a, &S::baz);
+}
diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C
new file mode 100644
index 0000000..a850c55
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/ptrmem11.C
@@ -0,0 +1,21 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin PR c++/37093
+
+struct A {};
+
+template <int A::* p>
+int
+foo(A* q)
+{
+ return q->*p;
+}
+
+template <typename T>
+int
+bar(int T::* p)
+{
+ return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member)" }
+}
+
+int i = bar<A>(0);
+