Patchwork C++ PATCH for c++/48582 (core 342: null pointer values as template non-type arguments)

login
register
mail settings
Submitter Jason Merrill
Date Aug. 28, 2011, 3:38 p.m.
Message ID <4E5A60F5.6010701@redhat.com>
Download mbox | patch
Permalink /patch/111910/
State New
Headers show

Comments

Jason Merrill - Aug. 28, 2011, 3:38 p.m.
DR 342 allows null pointer values as non-type arguments in C++11; this 
patch implements that.  We mangle such arguments as a cast from 0 like 
the EDG compiler does.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit c51119b8511eb6988e59c7decdd4c3817b9074bb
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Aug 26 22:38:12 2011 -0400

    	Core DR 342
    	PR c++/48582
    	* pt.c (check_valid_ptrmem_cst_expr): A null member pointer value
    	is valid in C++11.
    	(convert_nontype_argument): Likewise.  Implicitly convert nullptr
    	and do constant folding.
    	* mangle.c (write_template_arg_literal): Mangle null member
    	pointer values as 0.
    	* call.c (null_member_pointer_value_p): New.
    	* cp-tree.h: Declare it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index dc35824..8421260 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -553,6 +553,23 @@  null_ptr_cst_p (tree t)
   return false;
 }
 
+/* Returns true iff T is a null member pointer value (4.11).  */
+
+bool
+null_member_pointer_value_p (tree t)
+{
+  tree type = TREE_TYPE (t);
+  if (!type)
+    return false;
+  else if (TYPE_PTRMEMFUNC_P (type))
+    return (TREE_CODE (t) == CONSTRUCTOR
+	    && integer_zerop (CONSTRUCTOR_ELT (t, 0)->value));
+  else if (TYPE_PTRMEM_P (type))
+    return integer_all_onesp (t);
+  else
+    return false;
+}
+
 /* Returns nonzero if PARMLIST consists of only default parms,
    ellipsis, and/or undeduced parameter packs.  */
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8595943..d125642 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4722,6 +4722,7 @@  extern tree build_addr_func			(tree);
 extern tree build_call_a			(tree, int, tree*);
 extern tree build_call_n			(tree, int, ...);
 extern bool null_ptr_cst_p			(tree);
+extern bool null_member_pointer_value_p		(tree);
 extern bool sufficient_parms_p			(const_tree);
 extern tree type_decays_to			(tree);
 extern tree build_user_type_conversion		(tree, tree, int);
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 4c7cc79..1fcd999 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2762,29 +2762,34 @@  write_template_arg_literal (const tree value)
   write_char ('L');
   write_type (TREE_TYPE (value));
 
-  switch (TREE_CODE (value))
-    {
-    case CONST_DECL:
-      write_integer_cst (DECL_INITIAL (value));
-      break;
+  /* Write a null member pointer value as (type)0, regardless of its
+     real representation.  */
+  if (null_member_pointer_value_p (value))
+    write_integer_cst (integer_zero_node);
+  else
+    switch (TREE_CODE (value))
+      {
+      case CONST_DECL:
+	write_integer_cst (DECL_INITIAL (value));
+	break;
 
-    case INTEGER_CST:
-      gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
-		  || integer_zerop (value) || integer_onep (value));
-      write_integer_cst (value);
-      break;
+      case INTEGER_CST:
+	gcc_assert (!same_type_p (TREE_TYPE (value), boolean_type_node)
+		    || integer_zerop (value) || integer_onep (value));
+	write_integer_cst (value);
+	break;
 
-    case REAL_CST:
-      write_real_cst (value);
-      break;
+      case REAL_CST:
+	write_real_cst (value);
+	break;
 
-    case STRING_CST:
-      sorry ("string literal in function template signature");
-      break;
+      case STRING_CST:
+	sorry ("string literal in function template signature");
+	break;
 
-    default:
-      gcc_unreachable ();
-    }
+      default:
+	gcc_unreachable ();
+      }
 
   write_char ('E');
 }
@@ -2845,7 +2850,8 @@  write_template_arg (tree node)
     /* A template appearing as a template arg is a template template arg.  */
     write_template_template_arg (node);
   else if ((TREE_CODE_CLASS (code) == tcc_constant && code != PTRMEM_CST)
-	   || (abi_version_at_least (2) && code == CONST_DECL))
+	   || (abi_version_at_least (2) && code == CONST_DECL)
+	   || null_member_pointer_value_p (node))
     write_template_arg_literal (node);
   else if (DECL_P (node))
     {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3c6b2c5..1f43ff1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5240,6 +5240,8 @@  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;
+  if (cxx_dialect >= cxx0x && null_member_pointer_value_p (expr))
+    return true;
   if (complain & tf_error)
     {
       error ("%qE is not a valid template argument for type %qT",
@@ -5550,6 +5552,17 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
   else
     expr = mark_rvalue_use (expr);
 
+  /* 14.3.2/5: The null pointer{,-to-member} conversion is applied
+     to a non-type argument of "nullptr".  */
+  if (expr == nullptr_node
+      && (TYPE_PTR_P (type) || TYPE_PTR_TO_MEMBER_P (type)))
+    expr = convert (type, expr);
+
+  /* In C++11, non-type template arguments can be arbitrary constant
+     expressions.  But don't fold a PTRMEM_CST to a CONSTRUCTOR yet.  */
+  if (cxx_dialect >= cxx0x && TREE_CODE (expr) != PTRMEM_CST)
+    expr = maybe_constant_value (expr);
+
   /* HACK: Due to double coercion, we can get a
      NOP_EXPR<REFERENCE_TYPE>(ADDR_EXPR<POINTER_TYPE> (arg)) here,
      which is the tree that we built on the first call (see
@@ -5658,6 +5671,8 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       if (DECL_P (expr) && DECL_TEMPLATE_PARM_P (expr))
 	/* Non-type template parameters are OK.  */
 	;
+      else if (cxx_dialect >= cxx0x && integer_zerop (expr))
+	/* Null pointer values are OK in C++11.  */;
       else if (TREE_CODE (expr) != ADDR_EXPR
 	       && TREE_CODE (expr_type) != ARRAY_TYPE)
 	{
@@ -5785,6 +5800,10 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
 	    return error_mark_node;
 	}
 
+      if (cxx_dialect >= cxx0x && integer_zerop (expr))
+	/* Null pointer values are OK in C++11.  */
+	return perform_qualification_conversions (type, expr);
+
       expr = convert_nontype_argument_function (type, expr);
       if (!expr || expr == error_mark_node)
 	return expr;
diff --git a/gcc/testsuite/g++.dg/abi/mangle50.C b/gcc/testsuite/g++.dg/abi/mangle50.C
new file mode 100644
index 0000000..df7afb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle50.C
@@ -0,0 +1,25 @@ 
+// DR 342, PR c++/48582
+// { dg-options -std=c++0x }
+
+struct A;
+template < void * = nullptr > void f() { }
+template < void (A::*)() = nullptr > void g() { }
+template < int A::* = nullptr > void h() { }
+
+int main()
+{
+  // { dg-final { scan-assembler "_Z1fILPv0EEvv" } }
+  f();
+  f<nullptr>();
+
+  // { dg-final { scan-assembler "_Z1gILM1AFvvE0EEvv" } }
+  g();
+  g<nullptr>();
+
+  // { dg-final { scan-assembler "_Z1fILPv0EEvv" } }
+  h();
+  h<nullptr>();
+
+  constexpr void * ptr = nullptr;
+  f<ptr>();
+}