This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA] PR c++/37093


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);
+


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]