diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 10e64ef7f35..2e0d6ab9305 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2011-08-26 Jason Merrill + + 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. + 2011-08-25 Jason Merrill * call.c (convert_like_real): Remove redundant complain checks. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index dc3582414f5..84212603b1a 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 85959439397..d1256424def 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 4c7cc79d4e3..1fcd999e585 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 3c6b2c54a99..1f43ff1fbf0 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(ADDR_EXPR (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/ChangeLog b/gcc/testsuite/ChangeLog index 34816571d37..03a45a4ee07 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-08-26 Jason Merrill + + Core DR 342 + PR c++/48582 + * g++.dg/abi/mangle50.C: New. + 2011-08-27 Uros Bizjak PR target/50202 diff --git a/gcc/testsuite/g++.dg/abi/mangle50.C b/gcc/testsuite/g++.dg/abi/mangle50.C new file mode 100644 index 00000000000..df7afb97edc --- /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(); + + // { dg-final { scan-assembler "_Z1gILM1AFvvE0EEvv" } } + g(); + g(); + + // { dg-final { scan-assembler "_Z1fILPv0EEvv" } } + h(); + h(); + + constexpr void * ptr = nullptr; + f(); +}