Add support for C++0x nullptr.

gcc:
	* c-common.c (c_common_reswords): Add nullptr.
	* c-common.h: Add RID_NULLPTR.  Reorganize C++0x rids.
	* dwarf2out.c (is_base_type): Handle NULLPTR_TYPE.
	(gen_type_die_with_usage): Likewise.
	* dbxout.c (dbxout_type): Likewise.
	* sdbout.c (plain_type_1): Likewise.
gcc/cp:
	* cp-tree.def: Add NULLPTR_TYPE.
	* cp-tree.h: Add nullptr_node.
	(cp_tree_index): Add CPTI_NULLPTR.
	(SCALAR_TYPE_P): Add NULLPTR_TYPE.
	* call.c (null_ptr_cst_p): Handle nullptr.
	(standard_conversion): Likewise.
	(convert_arg_to_ellipsis): Likewise.
	* mangle.c (write_type): Likewise.
	* name-lookup.c (arg_assoc_type): Likewise.
	* parser.c (cp_parser_primary_expression): Likewise.
	* typeck.c (cp_build_binary_op): Likewise.
	(build_reinterpret_cast_1): Likewise.
	* error.c (dump_type): Likewise.
	(dump_type_prefix, dump_type_suffix): Likewise.
	* decl.c (cxx_init_decl_processing): Likewise.
	* cxx-pretty-print.c (pp_cxx_constant): Likewise.
	* cvt.c (ocp_convert): Likewise.
	* rtti.c (typeinfo_in_lib_p, emit_support_tinfos): Put
	nullptr_t tinfo in libsupc++.
libstdc++-v3:
	* config/abi/pre/gnu.ver: Add typeinfo for decltype(nullptr).
libiberty:
	* cp-demangle.c (cplus_demangle_builtin_types): Add nullptr.
	(cplus_demangle_type): Handle nullptr.

From-SVN: r159131
This commit is contained in:
Jason Merrill 2010-05-06 16:51:52 -04:00
parent 0d1141a39e
commit 14c2101daa
52 changed files with 536 additions and 33 deletions

View File

@ -1,3 +1,13 @@
2010-05-06 Magnus Fromreide <magfr@lysator.liu.se>
Jason Merrill <jason@redhat.com>
* c-common.c (c_common_reswords): Add nullptr.
* c-common.h: Add RID_NULLPTR. Reorganize C++0x rids.
* dwarf2out.c (is_base_type): Handle NULLPTR_TYPE.
(gen_type_die_with_usage): Likewise.
* dbxout.c (dbxout_type): Likewise.
* sdbout.c (plain_type_1): Likewise.
2010-05-06 Jason Merrill <jason@redhat.com> 2010-05-06 Jason Merrill <jason@redhat.com>
* gimplify.c (gimplify_expr): Set GS_ALL_DONE when appropriate. * gimplify.c (gimplify_expr): Set GS_ALL_DONE when appropriate.

View File

@ -656,6 +656,7 @@ const struct c_common_resword c_common_reswords[] =
{ "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN }, { "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
{ "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN }, { "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
{ "new", RID_NEW, D_CXXONLY | D_CXXWARN }, { "new", RID_NEW, D_CXXONLY | D_CXXWARN },
{ "nullptr", RID_NULLPTR, D_CXXONLY | D_CXX0X | D_CXXWARN },
{ "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN }, { "operator", RID_OPERATOR, D_CXXONLY | D_CXXWARN },
{ "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN }, { "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN },
{ "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN }, { "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN },

View File

@ -114,7 +114,7 @@ enum rid
RID_IS_UNION, RID_IS_UNION,
/* C++0x */ /* C++0x */
RID_STATIC_ASSERT, RID_CONSTEXPR, RID_DECLTYPE, RID_CONSTEXPR, RID_DECLTYPE, RID_NULLPTR, RID_STATIC_ASSERT,
/* Objective-C */ /* Objective-C */
RID_AT_ENCODE, RID_AT_END, RID_AT_ENCODE, RID_AT_END,
@ -155,8 +155,8 @@ enum rid
RID_FIRST_MODIFIER = RID_STATIC, RID_FIRST_MODIFIER = RID_STATIC,
RID_LAST_MODIFIER = RID_ONEWAY, RID_LAST_MODIFIER = RID_ONEWAY,
RID_FIRST_CXX0X = RID_STATIC_ASSERT, RID_FIRST_CXX0X = RID_CONSTEXPR,
RID_LAST_CXX0X = RID_DECLTYPE, RID_LAST_CXX0X = RID_STATIC_ASSERT,
RID_FIRST_AT = RID_AT_ENCODE, RID_FIRST_AT = RID_AT_ENCODE,
RID_LAST_AT = RID_AT_IMPLEMENTATION, RID_LAST_AT = RID_AT_IMPLEMENTATION,
RID_FIRST_PQ = RID_IN, RID_FIRST_PQ = RID_IN,

View File

@ -1,3 +1,27 @@
2010-05-06 Magnus Fromreide <magfr@lysator.liu.se>
Jason Merrill <jason@redhat.com>
Add support for C++0x nullptr.
* cp-tree.def: Add NULLPTR_TYPE.
* cp-tree.h: Add nullptr_node.
(cp_tree_index): Add CPTI_NULLPTR.
(SCALAR_TYPE_P): Add NULLPTR_TYPE.
* call.c (null_ptr_cst_p): Handle nullptr.
(standard_conversion): Likewise.
(convert_arg_to_ellipsis): Likewise.
* mangle.c (write_type): Likewise.
* name-lookup.c (arg_assoc_type): Likewise.
* parser.c (cp_parser_primary_expression): Likewise.
* typeck.c (cp_build_binary_op): Likewise.
(build_reinterpret_cast_1): Likewise.
* error.c (dump_type): Likewise.
(dump_type_prefix, dump_type_suffix): Likewise.
* decl.c (cxx_init_decl_processing): Likewise.
* cxx-pretty-print.c (pp_cxx_constant): Likewise.
* cvt.c (ocp_convert): Likewise.
* rtti.c (typeinfo_in_lib_p, emit_support_tinfos): Put
nullptr_t tinfo in libsupc++.
2010-05-06 Jason Merrill <jason@redhat.com> 2010-05-06 Jason Merrill <jason@redhat.com>
* semantics.c (simplify_aggr_init_expr): Use INIT_EXPR. * semantics.c (simplify_aggr_init_expr): Use INIT_EXPR.

View File

@ -460,9 +460,11 @@ null_ptr_cst_p (tree t)
/* [conv.ptr] /* [conv.ptr]
A null pointer constant is an integral constant expression A null pointer constant is an integral constant expression
(_expr.const_) rvalue of integer type that evaluates to zero. */ (_expr.const_) rvalue of integer type that evaluates to zero or
an rvalue of type std::nullptr_t. */
t = integral_constant_value (t); t = integral_constant_value (t);
if (t == null_node) if (t == null_node
|| TREE_CODE (TREE_TYPE (t)) == NULLPTR_TYPE)
return true; return true;
if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t)) if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t))
{ {
@ -776,7 +778,12 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
if (same_type_p (from, to)) if (same_type_p (from, to))
return conv; return conv;
if ((tcode == POINTER_TYPE || TYPE_PTR_TO_MEMBER_P (to)) /* [conv.ptr]
A null pointer constant can be converted to a pointer type; ... A
null pointer constant of integral type can be converted to an
rvalue of type std::nullptr_t. */
if ((tcode == POINTER_TYPE || TYPE_PTR_TO_MEMBER_P (to)
|| tcode == NULLPTR_TYPE)
&& expr && null_ptr_cst_p (expr)) && expr && null_ptr_cst_p (expr))
conv = build_conv (ck_std, to, conv); conv = build_conv (ck_std, to, conv);
else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE) else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
@ -911,17 +918,20 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
An rvalue of arithmetic, unscoped enumeration, pointer, or An rvalue of arithmetic, unscoped enumeration, pointer, or
pointer to member type can be converted to an rvalue of type pointer to member type can be converted to an rvalue of type
bool. */ bool. ... An rvalue of type std::nullptr_t can be converted
to an rvalue of type bool; */
if (ARITHMETIC_TYPE_P (from) if (ARITHMETIC_TYPE_P (from)
|| UNSCOPED_ENUM_P (from) || UNSCOPED_ENUM_P (from)
|| fcode == POINTER_TYPE || fcode == POINTER_TYPE
|| TYPE_PTR_TO_MEMBER_P (from)) || TYPE_PTR_TO_MEMBER_P (from)
|| fcode == NULLPTR_TYPE)
{ {
conv = build_conv (ck_std, to, conv); conv = build_conv (ck_std, to, conv);
if (fcode == POINTER_TYPE if (fcode == POINTER_TYPE
|| TYPE_PTRMEM_P (from) || TYPE_PTRMEM_P (from)
|| (TYPE_PTRMEMFUNC_P (from) || (TYPE_PTRMEMFUNC_P (from)
&& conv->rank < cr_pbool)) && conv->rank < cr_pbool)
|| fcode == NULLPTR_TYPE)
conv->rank = cr_pbool; conv->rank = cr_pbool;
return conv; return conv;
} }
@ -5192,6 +5202,8 @@ convert_arg_to_ellipsis (tree arg)
< TYPE_PRECISION (double_type_node)) < TYPE_PRECISION (double_type_node))
&& !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (arg)))) && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (arg))))
arg = convert_to_real (double_type_node, arg); arg = convert_to_real (double_type_node, arg);
else if (TREE_CODE (TREE_TYPE (arg)) == NULLPTR_TYPE)
arg = null_pointer_node;
else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg))) else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg)))
arg = perform_integral_promotions (arg); arg = perform_integral_promotions (arg);
@ -6788,9 +6800,8 @@ compare_ics (conversion *ics1, conversion *ics2)
Two conversion sequences with the same rank are indistinguishable Two conversion sequences with the same rank are indistinguishable
unless one of the following rules applies: unless one of the following rules applies:
--A conversion that is not a conversion of a pointer, or pointer --A conversion that does not a convert a pointer, pointer to member,
to member, to bool is better than another conversion that is such or std::nullptr_t to bool is better than one that does.
a conversion.
The ICS_STD_RANK automatically handles the pointer-to-bool rule, The ICS_STD_RANK automatically handles the pointer-to-bool rule,
so that we do not have to check it explicitly. */ so that we do not have to check it explicitly. */

View File

@ -449,6 +449,9 @@ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
instantiation time. */ instantiation time. */
DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0) DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0)
/* The type of a nullptr expression. This is a C++0x extension. */
DEFTREECODE (NULLPTR_TYPE, "decltype(nullptr)", tcc_type, 0)
/* /*
Local variables: Local variables:
mode:c mode:c

View File

@ -775,6 +775,8 @@ enum cp_tree_index
CPTI_KEYED_CLASSES, CPTI_KEYED_CLASSES,
CPTI_NULLPTR,
CPTI_MAX CPTI_MAX
}; };
@ -809,6 +811,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
#define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL] #define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL]
#define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL] #define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
#define current_aggr cp_global_trees[CPTI_AGGR_TAG] #define current_aggr cp_global_trees[CPTI_AGGR_TAG]
#define nullptr_node cp_global_trees[CPTI_NULLPTR]
/* We cache these tree nodes so as to call get_identifier less /* We cache these tree nodes so as to call get_identifier less
frequently. */ frequently. */
@ -3001,8 +3004,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
/* [basic.types] /* [basic.types]
Arithmetic types, enumeration types, pointer types, and Arithmetic types, enumeration types, pointer types,
pointer-to-member types, are collectively called scalar types. pointer-to-member types, and std::nullptr_t are collectively called
scalar types.
Keep these checks in ascending code order. */ Keep these checks in ascending code order. */
#define SCALAR_TYPE_P(TYPE) \ #define SCALAR_TYPE_P(TYPE) \
@ -3010,7 +3014,8 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
|| TREE_CODE (TYPE) == ENUMERAL_TYPE \ || TREE_CODE (TYPE) == ENUMERAL_TYPE \
|| ARITHMETIC_TYPE_P (TYPE) \ || ARITHMETIC_TYPE_P (TYPE) \
|| TYPE_PTR_P (TYPE) \ || TYPE_PTR_P (TYPE) \
|| TYPE_PTRMEMFUNC_P (TYPE)) || TYPE_PTRMEMFUNC_P (TYPE) \
|| TREE_CODE (TYPE) == NULLPTR_TYPE)
/* Determines whether this type is a C++0x scoped enumeration /* Determines whether this type is a C++0x scoped enumeration
type. Scoped enumerations types are introduced via "enum class" or type. Scoped enumerations types are introduced via "enum class" or

View File

@ -704,6 +704,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags)
return fold_if_not_in_template (convert_to_integer (type, e)); return fold_if_not_in_template (convert_to_integer (type, e));
} }
if (code == NULLPTR_TYPE && e && null_ptr_cst_p (e))
return nullptr_node;
if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
return fold_if_not_in_template (cp_convert_to_pointer (type, e)); return fold_if_not_in_template (cp_convert_to_pointer (type, e));
if (code == VECTOR_TYPE) if (code == VECTOR_TYPE)

View File

@ -339,6 +339,14 @@ pp_cxx_constant (cxx_pretty_printer *pp, tree t)
} }
break; break;
case INTEGER_CST:
if (TREE_CODE (TREE_TYPE (t)) == NULLPTR_TYPE)
{
pp_string (pp, "nullptr");
break;
}
/* else fall through. */
default: default:
pp_c_constant (pp_c_base (pp), t); pp_c_constant (pp_c_base (pp), t);
break; break;

View File

@ -3526,6 +3526,17 @@ cxx_init_decl_processing (void)
push_cp_library_fn (VEC_NEW_EXPR, newtype); push_cp_library_fn (VEC_NEW_EXPR, newtype);
global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype); global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype);
push_cp_library_fn (VEC_DELETE_EXPR, deltype); push_cp_library_fn (VEC_DELETE_EXPR, deltype);
{
tree nullptr_type_node = make_node (NULLPTR_TYPE);
TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
TYPE_SIZE_UNIT (nullptr_type_node) = size_int (GET_MODE_SIZE (ptr_mode));
TYPE_UNSIGNED (nullptr_type_node) = 1;
TYPE_PRECISION (nullptr_type_node) = GET_MODE_BITSIZE (ptr_mode);
SET_TYPE_MODE (nullptr_type_node, Pmode);
nullptr_node = make_node (INTEGER_CST);
TREE_TYPE (nullptr_node) = nullptr_type_node;
}
} }
abort_fndecl abort_fndecl

View File

@ -475,6 +475,10 @@ dump_type (tree t, int flags)
pp_cxx_right_paren (cxx_pp); pp_cxx_right_paren (cxx_pp);
break; break;
case NULLPTR_TYPE:
pp_string (cxx_pp, "std::nullptr_t");
break;
default: default:
pp_unsupported_tree (cxx_pp, t); pp_unsupported_tree (cxx_pp, t);
/* Fall through to error. */ /* Fall through to error. */
@ -703,6 +707,7 @@ dump_type_prefix (tree t, int flags)
case DECLTYPE_TYPE: case DECLTYPE_TYPE:
case TYPE_PACK_EXPANSION: case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE: case FIXED_POINT_TYPE:
case NULLPTR_TYPE:
dump_type (t, flags); dump_type (t, flags);
pp_base (cxx_pp)->padding = pp_before; pp_base (cxx_pp)->padding = pp_before;
break; break;
@ -805,6 +810,7 @@ dump_type_suffix (tree t, int flags)
case DECLTYPE_TYPE: case DECLTYPE_TYPE:
case TYPE_PACK_EXPANSION: case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE: case FIXED_POINT_TYPE:
case NULLPTR_TYPE:
break; break;
default: default:

View File

@ -1759,6 +1759,7 @@ write_local_name (tree function, const tree local_entity,
<type> ::= Dt <expression> # decltype of an id-expression or <type> ::= Dt <expression> # decltype of an id-expression or
# class member access # class member access
<type> ::= DT <expression> # decltype of an expression <type> ::= DT <expression> # decltype of an expression
<type> ::= Dn # decltype of nullptr
TYPE is a type node. */ TYPE is a type node. */
@ -1932,6 +1933,10 @@ write_type (tree type)
write_char ('E'); write_char ('E');
break; break;
case NULLPTR_TYPE:
write_string ("Dn");
break;
case TYPEOF_TYPE: case TYPEOF_TYPE:
sorry ("mangling typeof, use decltype instead"); sorry ("mangling typeof, use decltype instead");
break; break;

View File

@ -4859,6 +4859,7 @@ arg_assoc_type (struct arg_lookup *k, tree type)
case BOOLEAN_TYPE: case BOOLEAN_TYPE:
case FIXED_POINT_TYPE: case FIXED_POINT_TYPE:
case DECLTYPE_TYPE: case DECLTYPE_TYPE:
case NULLPTR_TYPE:
return false; return false;
case RECORD_TYPE: case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type)) if (TYPE_PTRMEMFUNC_P (type))

View File

@ -3368,6 +3368,11 @@ cp_parser_primary_expression (cp_parser *parser,
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);
return null_node; return null_node;
/* The `nullptr' literal. */
case RID_NULLPTR:
cp_lexer_consume_token (parser->lexer);
return nullptr_node;
/* Recognize the `this' keyword. */ /* Recognize the `this' keyword. */
case RID_THIS: case RID_THIS:
cp_lexer_consume_token (parser->lexer); cp_lexer_consume_token (parser->lexer);

View File

@ -1044,6 +1044,7 @@ typeinfo_in_lib_p (tree type)
case BOOLEAN_TYPE: case BOOLEAN_TYPE:
case REAL_TYPE: case REAL_TYPE:
case VOID_TYPE: case VOID_TYPE:
case NULLPTR_TYPE:
return true; return true;
default: default:
@ -1449,6 +1450,9 @@ create_tinfo_types (void)
void void
emit_support_tinfos (void) emit_support_tinfos (void)
{ {
/* Dummy static variable so we can put nullptr in the array; it will be
set before we actually start to walk the array. */
static tree nullptr_type_node;
static tree *const fundamentals[] = static tree *const fundamentals[] =
{ {
&void_type_node, &void_type_node,
@ -1461,6 +1465,7 @@ emit_support_tinfos (void)
&long_long_integer_type_node, &long_long_unsigned_type_node, &long_long_integer_type_node, &long_long_unsigned_type_node,
&float_type_node, &double_type_node, &long_double_type_node, &float_type_node, &double_type_node, &long_double_type_node,
&dfloat32_type_node, &dfloat64_type_node, &dfloat128_type_node, &dfloat32_type_node, &dfloat64_type_node, &dfloat128_type_node,
&nullptr_type_node,
0 0
}; };
int ix; int ix;
@ -1477,6 +1482,7 @@ emit_support_tinfos (void)
if (!dtor || DECL_EXTERNAL (dtor)) if (!dtor || DECL_EXTERNAL (dtor))
return; return;
doing_runtime = 1; doing_runtime = 1;
nullptr_type_node = TREE_TYPE (nullptr_node);
for (ix = 0; fundamentals[ix]; ix++) for (ix = 0; fundamentals[ix]; ix++)
{ {
tree bltn = *fundamentals[ix]; tree bltn = *fundamentals[ix];

View File

@ -3993,6 +3993,9 @@ cp_build_binary_op (location_t location,
} }
result_type = type1; result_type = type1;
} }
else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
/* One of the operands must be of nullptr_t type. */
result_type = TREE_TYPE (nullptr_node);
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{ {
result_type = type0; result_type = type0;
@ -4192,12 +4195,13 @@ cp_build_binary_op (location_t location,
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
result_type = composite_pointer_type (type0, type1, op0, op1, result_type = composite_pointer_type (type0, type1, op0, op1,
CPO_COMPARISON, complain); CPO_COMPARISON, complain);
else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
&& integer_zerop (op1))
result_type = type0; result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0))
&& integer_zerop (op0))
result_type = type1; result_type = type1;
else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
/* One of the operands must be of nullptr_t type. */
result_type = TREE_TYPE (nullptr_node);
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE) else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{ {
result_type = type0; result_type = type0;
@ -6020,8 +6024,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
/* [expr.reinterpret.cast] /* [expr.reinterpret.cast]
A pointer can be converted to any integral type large enough to A pointer can be converted to any integral type large enough to
hold it. */ hold it. ... A value of type std::nullptr_t can be converted to
if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype)) an integral type; the conversion has the same meaning and
validity as a conversion of (void*)0 to the integral type. */
if (CP_INTEGRAL_TYPE_P (type)
&& (TYPE_PTR_P (intype) || TREE_CODE (intype) == NULLPTR_TYPE))
{ {
if (TYPE_PRECISION (type) < TYPE_PRECISION (intype)) if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
{ {
@ -6031,6 +6038,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
else else
return error_mark_node; return error_mark_node;
} }
if (TREE_CODE (intype) == NULLPTR_TYPE)
return build_int_cst (type, 0);
} }
/* [expr.reinterpret.cast] /* [expr.reinterpret.cast]
A value of integral or enumeration type can be explicitly A value of integral or enumeration type can be explicitly

View File

@ -1867,6 +1867,7 @@ dbxout_type (tree type, int full)
{ {
case VOID_TYPE: case VOID_TYPE:
case LANG_TYPE: case LANG_TYPE:
case NULLPTR_TYPE:
/* For a void type, just define it as itself; i.e., "5=5". /* For a void type, just define it as itself; i.e., "5=5".
This makes us consider it defined This makes us consider it defined
without saying what it is. The debugger will make it without saying what it is. The debugger will make it

View File

@ -12108,6 +12108,7 @@ is_base_type (tree type)
case ENUMERAL_TYPE: case ENUMERAL_TYPE:
case FUNCTION_TYPE: case FUNCTION_TYPE:
case METHOD_TYPE: case METHOD_TYPE:
case NULLPTR_TYPE:
case POINTER_TYPE: case POINTER_TYPE:
case REFERENCE_TYPE: case REFERENCE_TYPE:
case OFFSET_TYPE: case OFFSET_TYPE:
@ -19171,6 +19172,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
when appropriate. */ when appropriate. */
return; return;
case NULLPTR_TYPE:
{
dw_die_ref type_die = lookup_type_die (type);
if (type_die == NULL)
{
type_die = new_die (DW_TAG_unspecified_type, comp_unit_die, type);
add_name_attribute (type_die, "decltype(nullptr)");
equate_type_number_to_die (type, type_die);
}
}
return;
case VOID_TYPE: case VOID_TYPE:
case INTEGER_TYPE: case INTEGER_TYPE:
case REAL_TYPE: case REAL_TYPE:

View File

@ -3077,7 +3077,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
it is invalid to pass a non-present argument on, even it is invalid to pass a non-present argument on, even
though there is no technical reason for this in gfortran. though there is no technical reason for this in gfortran.
See Fortran 2003, Section 12.4.1.6 item (7)+(8). */ See Fortran 2003, Section 12.4.1.6 item (7)+(8). */
tree present, nullptr, type; tree present, null_ptr, type;
if (attr->allocatable if (attr->allocatable
&& (fsym == NULL || !fsym->attr.allocatable)) && (fsym == NULL || !fsym->attr.allocatable))
@ -3101,10 +3101,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
present = fold_build2 (EQ_EXPR, boolean_type_node, present, present = fold_build2 (EQ_EXPR, boolean_type_node, present,
fold_convert (type, null_pointer_node)); fold_convert (type, null_pointer_node));
type = TREE_TYPE (parmse.expr); type = TREE_TYPE (parmse.expr);
nullptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr, null_ptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr,
fold_convert (type, null_pointer_node)); fold_convert (type, null_pointer_node));
cond = fold_build2 (TRUTH_ORIF_EXPR, boolean_type_node, cond = fold_build2 (TRUTH_ORIF_EXPR, boolean_type_node,
present, nullptr); present, null_ptr);
} }
else else
{ {

View File

@ -493,6 +493,7 @@ plain_type_1 (tree type, int level)
switch (TREE_CODE (type)) switch (TREE_CODE (type))
{ {
case VOID_TYPE: case VOID_TYPE:
case NULLPTR_TYPE:
return T_VOID; return T_VOID;
case BOOLEAN_TYPE: case BOOLEAN_TYPE:
case INTEGER_TYPE: case INTEGER_TYPE:

View File

@ -1,3 +1,31 @@
2010-05-06 Magnus Fromreide <magfr@lysator.liu.se>
Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/nullptr01.C: New.
* g++.dg/cpp0x/nullptr02.C: New.
* g++.dg/cpp0x/nullptr03.C: New.
* g++.dg/cpp0x/nullptr04.C: New.
* g++.dg/cpp0x/nullptr05.C: New.
* g++.dg/cpp0x/nullptr06.C: New.
* g++.dg/cpp0x/nullptr07.C: New.
* g++.dg/cpp0x/nullptr08.C: New.
* g++.dg/cpp0x/nullptr09.C: New.
* g++.dg/cpp0x/nullptr10.C: New.
* g++.dg/cpp0x/nullptr11.C: New.
* g++.dg/cpp0x/nullptr12.C: New.
* g++.dg/cpp0x/nullptr13.C: New.
* g++.dg/cpp0x/nullptr14.C: New.
* g++.dg/cpp0x/nullptr15.C: New.
* g++.dg/cpp0x/nullptr16.C: New.
* g++.dg/cpp0x/nullptr17.C: New.
* g++.dg/cpp0x/nullptr18.C: New.
* g++.dg/cpp0x/nullptr19.C: New.
* g++.dg/cpp0x/nullptr20.C: New.
* g++.dg/cpp0x/nullptr21.C: New.
* g++.dg/cpp0x/nullptr22.C: New.
* g++.dg/debug/nullptr01.C: New.
* gcc.dg/Wcxx-compat-2.c: Test nullptr and constexpr.
2010-05-06 Paolo Carlini <paolo.carlini@oracle.com> 2010-05-06 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/40406 PR c++/40406

View File

@ -0,0 +1,8 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test assignment to pointer
char* const cp1 = nullptr;
char* const cp2 = __null;
char* const cp3 = 0;

View File

@ -0,0 +1,10 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test assignment to nullptr_t
typedef decltype(nullptr) nullptr_t;
const nullptr_t np1 = nullptr;
const nullptr_t np2 = __null;
const nullptr_t np3 = 0;

View File

@ -0,0 +1,6 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test assignment to int
const int n = nullptr; // { dg-error "cannot convert " }

View File

@ -0,0 +1,9 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test cast to int
const int n4 = static_cast<const int>(nullptr); // { dg-error "invalid static_cast " }
const short int n5 = reinterpret_cast<short int>(nullptr); // { dg-error "loses precision" }
const long int n6 = reinterpret_cast<long int>(nullptr);
const long int n7 = (long int)nullptr;

View File

@ -0,0 +1,12 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test assignment to method pointer
class F { };
typedef void (F::*pmf)();
const pmf pmf1 = nullptr;
const pmf pmf2 = __null;
const pmf pmf3 = 0;

View File

@ -0,0 +1,13 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test compare to pointer
#define assert_true(b) do { char c[2 * bool(b) - 1]; } while(0)
char* const cp1 = nullptr;
void fun()
{
assert_true(cp1 == nullptr);
}

View File

@ -0,0 +1,12 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test compare to int
void fun()
{
int n = 0;
if( n == nullptr ); // { dg-error "invalid operands of types " }
const int m = 1;
if( m == nullptr ); // { dg-error "invalid operands of types " }
}

View File

@ -0,0 +1,11 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test conversion to bool
#define assert_true(b) do { char c[2 * bool(b) - 1]; } while(0)
void fun()
{
assert_true(nullptr ? false : true);
}

View File

@ -0,0 +1,9 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test compare to literal 0
void fun()
{
if( nullptr == 0 );
}

View File

@ -0,0 +1,10 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test arithmetic operations
void fun()
{
nullptr = 0; // { dg-error "lvalue required as left operand" }
nullptr + 2; // { dg-error "invalid operands of types " }
}

View File

@ -0,0 +1,17 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test relational operators
#define assert_true(b) do { char c[2 * bool(b) - 1]; } while(0)
#define assert_false(b) do { char c[1 - 2 * bool(b)]; } while(0)
void fun()
{
assert_true(nullptr == nullptr);
assert_false(nullptr != nullptr);
assert_false(nullptr < nullptr);
assert_false(nullptr > nullptr);
assert_true(nullptr <= nullptr);
assert_true(nullptr >= nullptr);
}

View File

@ -0,0 +1,6 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test sizeof
static_assert(sizeof(nullptr) == sizeof(void*), "sizeof(nullptr) is wrong");

View File

@ -0,0 +1,11 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test typeid
#include <typeinfo>
void fun()
{
typeid(nullptr);
}

View File

@ -0,0 +1,23 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test overload preference char*/int
template <typename T, typename U> struct tType_equal;
template <typename T> struct tType_equal<T, T> { typedef void type; };
template <typename T, typename U>
inline typename tType_equal<T, U>::type
type_equal(U) { }
char* f( char* );
int f( int );
long int f( long int );
void test_f()
{
// Overloading cases
//
type_equal<char*>(f(nullptr));
type_equal<int>(f(0));
}

View File

@ -0,0 +1,21 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test template deduction
template <typename T, typename U> struct tType_equal;
template <typename T> struct tType_equal<T, T> { typedef void type; };
template <typename T, typename U>
inline typename tType_equal<T, U>::type
type_equal(U) { }
template<typename T> T* g( T* t );
void test_g()
{
// Deduction to nullptr_t, no deduction to pointer type
//
g(nullptr); // { dg-error "no matching function for call to " }
type_equal<float*>(g((float*)nullptr));
}

View File

@ -0,0 +1,22 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test template deduction
typedef decltype(nullptr) nullptr_t;
template <typename T, typename U> struct tType_equal;
template <typename T> struct tType_equal<T, T> { typedef void type; };
template <typename T, typename U>
inline typename tType_equal<T, U>::type
type_equal(U) { }
template<typename T> T h( T t );
void test_h()
{
type_equal<int>(h(0));
type_equal<nullptr_t>(h(nullptr));
type_equal<float*>(h((float*)nullptr));
}

View File

@ -0,0 +1,21 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test that bool is a better overload match than int
template <typename T, typename U> struct tType_equal;
template <typename T> struct tType_equal<T, T> { typedef void type; };
template <typename T, typename U>
inline typename tType_equal<T, U>::type
type_equal(U) { }
int i( int );
long int i( long int );
bool i( bool );
void test_i()
{
// Overload to bool, not int
type_equal<bool>(i(nullptr));
}

View File

@ -0,0 +1,19 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test overload of pointer versus bool when applied on a nullptr_t
template <typename T, typename U> struct tType_equal;
template <typename T> struct tType_equal<T, T> { typedef void type; };
template <typename T, typename U>
inline typename tType_equal<T, U>::type
type_equal(U) { }
char* j( char* );
bool j( bool );
void test_j()
{
type_equal<char*>(j(nullptr));
}

View File

@ -0,0 +1,15 @@
// { dg-do compile }
// { dg-options "-std=c++0x" }
// Test overload of pointer versus nullptr_t when applied on a literal 0/__null
typedef decltype(nullptr) nullptr_t;
char* k( char* ); /* { dg-message "note" } { dg-message "note" } */
nullptr_t k( nullptr_t ); /* { dg-message "note" } { dg-message "note" } */
void test_k()
{
k(0); /* { dg-error "is ambiguous" } */
k(__null); /* { dg-error "is ambiguous" } */
}

View File

@ -0,0 +1,17 @@
// { dg-do run }
// { dg-options "-std=c++0x" }
// Test passing to ellipisis
#include <cstdio>
#include <cstring>
int main()
{
char buf1[64];
char buf2[64];
std::snprintf(buf1, sizeof(buf1), "%p", (void*)0);
std::snprintf(buf2, sizeof(buf2), "%p", nullptr);
return std::strcmp(buf1, buf2) != 0;
}

View File

@ -0,0 +1,27 @@
// { dg-do run }
// { dg-options "-std=c++0x" }
// Test throw and catch
#include <cstdio>
typedef decltype(nullptr) nullptr_t;
int main()
{
try {
throw nullptr;
} catch (void*) {
printf("Test 1 Fail");
} catch (bool) {
printf("Test 1 Fail");
} catch (int) {
printf("Test 1 Fail");
} catch (long int) {
printf("Test 1 Fail");
} catch (nullptr_t) {
printf("Test 1 OK");
} catch (...) {
printf("Test 1 Fail");
} // { dg-output "Test 1 OK" }
}

View File

@ -0,0 +1,16 @@
// { dg-do compile }
// { dg-options "-std=c++0x -Wall -Wformat=2 -Wstrict-null-sentinel" }
// Test various warnings
void f1(const char*, ...) __attribute__((format(printf, 1, 2)));
void f2(const char*) __attribute__((nonnull));
void f3(const char*, ...) __attribute__((sentinel));
void f()
{
f1("%p", nullptr);
f2(nullptr); // { dg-warning "null argument where non-null required " }
f3("x", "y", __null); // { dg-warning "missing sentinel in function call" }
f3("x", "y", nullptr);
}

View File

@ -1,7 +1,9 @@
// { dg-options "-std=gnu++98 -Wc++0x-compat" } // { dg-options "-std=gnu++98 -Wc++0x-compat" }
int static_assert; // { dg-warning "will become a keyword" } int static_assert; // { dg-warning "will become a keyword" }
int nullptr; // { dg-warning "will become a keyword" }
void foo() void foo()
{ {
static_assert = 5; static_assert = 5;
nullptr = 5;
} }

View File

@ -0,0 +1,15 @@
// Test that debugging backends don't crash on NULLPTR_TYPE.
// { dg-options "-std=c++0x" }
typedef decltype(nullptr) nullptr_t;
nullptr_t np1;
void f (nullptr_t) { }
template <class T> struct A { };
template <class T> nullptr_t g(T t);
template <> nullptr_t g(A<nullptr_t>)
{
nullptr_t local;
}
// { dg-final { scan-assembler "_Z1fDn" } }
// { dg-final { scan-assembler "_Z1gI1AIDnEES1_T_" } }

View File

@ -7,6 +7,7 @@ int char16_t; /* { dg-warning "5:keyword" } */
int char32_t; /* { dg-warning "5:keyword" } */ int char32_t; /* { dg-warning "5:keyword" } */
int class; /* { dg-warning "5:keyword" } */ int class; /* { dg-warning "5:keyword" } */
int const_cast; /* { dg-warning "5:keyword" } */ int const_cast; /* { dg-warning "5:keyword" } */
int constexpr; /* { dg-warning "5:keyword" } */
int decltype; /* { dg-warning "5:keyword" } */ int decltype; /* { dg-warning "5:keyword" } */
int delete; /* { dg-warning "5:keyword" } */ int delete; /* { dg-warning "5:keyword" } */
int dynamic_cast; /* { dg-warning "5:keyword" } */ int dynamic_cast; /* { dg-warning "5:keyword" } */
@ -17,6 +18,7 @@ int friend; /* { dg-warning "5:keyword" } */
int mutable; /* { dg-warning "5:keyword" } */ int mutable; /* { dg-warning "5:keyword" } */
int namespace; /* { dg-warning "5:keyword" } */ int namespace; /* { dg-warning "5:keyword" } */
int new; /* { dg-warning "5:keyword" } */ int new; /* { dg-warning "5:keyword" } */
int nullptr; /* { dg-warning "5:keyword" } */
int operator; /* { dg-warning "5:keyword" } */ int operator; /* { dg-warning "5:keyword" } */
int private; /* { dg-warning "5:keyword" } */ int private; /* { dg-warning "5:keyword" } */
int protected; /* { dg-warning "5:keyword" } */ int protected; /* { dg-warning "5:keyword" } */

View File

@ -1,3 +1,10 @@
2010-05-06 Magnus Fromreide <magfr@lysator.liu.se>
Jason Merrill <jason@redhat.com>
* cp-demangle.c (cplus_demangle_builtin_types): Add nullptr.
(cplus_demangle_type): Handle nullptr.
* testsuite/demangle-expected: Test it.
2010-04-23 Pedro Alves <pedro@codesourcery.com> 2010-04-23 Pedro Alves <pedro@codesourcery.com>
* lbasename.c (lbasename): Split into ... * lbasename.c (lbasename): Split into ...

View File

@ -1987,6 +1987,8 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
/* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT }, /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT },
/* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT }, /* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT },
/* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, /* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT },
/* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
D_PRINT_DEFAULT },
}; };
CP_STATIC_IF_GLIBCPP_V3 CP_STATIC_IF_GLIBCPP_V3
@ -2221,6 +2223,12 @@ cplus_demangle_type (struct d_info *di)
ret = d_vector_type (di); ret = d_vector_type (di);
break; break;
case 'n':
/* decltype(nullptr) */
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
di->expansion += ret->u.s_builtin.type->len;
break;
default: default:
return NULL; return NULL;
} }

View File

@ -147,7 +147,7 @@ struct d_info
extern const struct demangle_operator_info cplus_demangle_operators[]; extern const struct demangle_operator_info cplus_demangle_operators[];
#endif #endif
#define D_BUILTIN_TYPE_COUNT (32) #define D_BUILTIN_TYPE_COUNT (33)
CP_STATIC_IF_GLIBCPP_V3 CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info const struct demangle_builtin_type_info

View File

@ -3938,6 +3938,9 @@ decltype ((operator+)({parm#1}, {parm#1})) f<A>(A)
--format=gnu-v3 --format=gnu-v3
_Z1hI1AEDTcldtfp_miEET_ _Z1hI1AEDTcldtfp_miEET_
decltype (({parm#1}.(operator-))()) h<A>(A) decltype (({parm#1}.(operator-))()) h<A>(A)
--format=gnu-v3
_Z1fDn
f(decltype(nullptr))
# #
# Ada (GNAT) tests. # Ada (GNAT) tests.
# #

View File

@ -1,3 +1,7 @@
2010-05-06 Jason Merrill <jason@redhat.com>
* config/abi/pre/gnu.ver: Add typeinfo for decltype(nullptr).
2010-05-06 Jonathan Wakely <jwakely.gcc@gmail.com> 2010-05-06 Jonathan Wakely <jwakely.gcc@gmail.com>
* include/bits/basic_string.h: Escape class names in doxygen docs. * include/bits/basic_string.h: Escape class names in doxygen docs.

View File

@ -1307,12 +1307,9 @@ CXXABI_1.3.3 {
CXXABI_1.3.4 { CXXABI_1.3.4 {
# typeinfo for decimal floating point types # typeinfo for decimal floating point types and decltype(nullptr)
_ZTID[fde]; _ZTID[fden];
_ZTIPD[fde]; _ZTIPD[fden];
_ZTIPKD[fde]; _ZTIPKD[fden];
_ZTID[fde];
_ZTIPD[fde];
_ZTIPKD[fde];
} CXXABI_1.3.3; } CXXABI_1.3.3;