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.
commit c51119b8511eb6988e59c7decdd4c3817b9074bb
Author: Jason Merrill <ja...@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>();
+}