diff options
Diffstat (limited to 'gcc')
46 files changed, 509 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a625399..94305fa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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> * gimplify.c (gimplify_expr): Set GS_ALL_DONE when appropriate. diff --git a/gcc/c-common.c b/gcc/c-common.c index d939e12..e11b6af 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -656,6 +656,7 @@ const struct c_common_resword c_common_reswords[] = { "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN }, { "namespace", RID_NAMESPACE, 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 }, { "private", RID_PRIVATE, D_CXX_OBJC | D_CXXWARN }, { "protected", RID_PROTECTED, D_CXX_OBJC | D_CXXWARN }, diff --git a/gcc/c-common.h b/gcc/c-common.h index 0da83d5..e32fa39 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -114,7 +114,7 @@ enum rid RID_IS_UNION, /* C++0x */ - RID_STATIC_ASSERT, RID_CONSTEXPR, RID_DECLTYPE, + RID_CONSTEXPR, RID_DECLTYPE, RID_NULLPTR, RID_STATIC_ASSERT, /* Objective-C */ RID_AT_ENCODE, RID_AT_END, @@ -155,8 +155,8 @@ enum rid RID_FIRST_MODIFIER = RID_STATIC, RID_LAST_MODIFIER = RID_ONEWAY, - RID_FIRST_CXX0X = RID_STATIC_ASSERT, - RID_LAST_CXX0X = RID_DECLTYPE, + RID_FIRST_CXX0X = RID_CONSTEXPR, + RID_LAST_CXX0X = RID_STATIC_ASSERT, RID_FIRST_AT = RID_AT_ENCODE, RID_LAST_AT = RID_AT_IMPLEMENTATION, RID_FIRST_PQ = RID_IN, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a5a7afa..860f4e7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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> * semantics.c (simplify_aggr_init_expr): Use INIT_EXPR. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e8fcc94..d74eb19 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -460,9 +460,11 @@ null_ptr_cst_p (tree t) /* [conv.ptr] 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); - if (t == null_node) + if (t == null_node + || TREE_CODE (TREE_TYPE (t)) == NULLPTR_TYPE) return true; 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)) 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)) conv = build_conv (ck_std, to, conv); 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 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) || UNSCOPED_ENUM_P (from) || 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); if (fcode == POINTER_TYPE || TYPE_PTRMEM_P (from) || (TYPE_PTRMEMFUNC_P (from) - && conv->rank < cr_pbool)) + && conv->rank < cr_pbool) + || fcode == NULLPTR_TYPE) conv->rank = cr_pbool; return conv; } @@ -5192,6 +5202,8 @@ convert_arg_to_ellipsis (tree arg) < TYPE_PRECISION (double_type_node)) && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (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))) arg = perform_integral_promotions (arg); @@ -6788,9 +6800,8 @@ compare_ics (conversion *ics1, conversion *ics2) Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies: - --A conversion that is not a conversion of a pointer, or pointer - to member, to bool is better than another conversion that is such - a conversion. + --A conversion that does not a convert a pointer, pointer to member, + or std::nullptr_t to bool is better than one that does. The ICS_STD_RANK automatically handles the pointer-to-bool rule, so that we do not have to check it explicitly. */ diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index c71f94c..c3e8208 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -449,6 +449,9 @@ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0) instantiation time. */ 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: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4fca633..22a7487 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -775,6 +775,8 @@ enum cp_tree_index CPTI_KEYED_CLASSES, + CPTI_NULLPTR, + CPTI_MAX }; @@ -809,6 +811,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL] #define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL] #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 frequently. */ @@ -3001,8 +3004,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* [basic.types] - Arithmetic types, enumeration types, pointer types, and - pointer-to-member types, are collectively called scalar types. + Arithmetic types, enumeration types, pointer types, + pointer-to-member types, and std::nullptr_t are collectively called + scalar types. Keep these checks in ascending code order. */ #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 \ || ARITHMETIC_TYPE_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 type. Scoped enumerations types are introduced via "enum class" or diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 5be0b8d..b357084 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -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)); } + if (code == NULLPTR_TYPE && e && null_ptr_cst_p (e)) + return nullptr_node; if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type)) return fold_if_not_in_template (cp_convert_to_pointer (type, e)); if (code == VECTOR_TYPE) diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 7b92272..55def21 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -339,6 +339,14 @@ pp_cxx_constant (cxx_pretty_printer *pp, tree t) } break; + case INTEGER_CST: + if (TREE_CODE (TREE_TYPE (t)) == NULLPTR_TYPE) + { + pp_string (pp, "nullptr"); + break; + } + /* else fall through. */ + default: pp_c_constant (pp_c_base (pp), t); break; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f9114a9..70b1041 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3526,6 +3526,17 @@ cxx_init_decl_processing (void) push_cp_library_fn (VEC_NEW_EXPR, newtype); global_delete_fndecl = push_cp_library_fn (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 diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 4ac70f7..3a03790 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -475,6 +475,10 @@ dump_type (tree t, int flags) pp_cxx_right_paren (cxx_pp); break; + case NULLPTR_TYPE: + pp_string (cxx_pp, "std::nullptr_t"); + break; + default: pp_unsupported_tree (cxx_pp, t); /* Fall through to error. */ @@ -703,6 +707,7 @@ dump_type_prefix (tree t, int flags) case DECLTYPE_TYPE: case TYPE_PACK_EXPANSION: case FIXED_POINT_TYPE: + case NULLPTR_TYPE: dump_type (t, flags); pp_base (cxx_pp)->padding = pp_before; break; @@ -805,6 +810,7 @@ dump_type_suffix (tree t, int flags) case DECLTYPE_TYPE: case TYPE_PACK_EXPANSION: case FIXED_POINT_TYPE: + case NULLPTR_TYPE: break; default: diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 187a656..05d5892 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -1759,6 +1759,7 @@ write_local_name (tree function, const tree local_entity, <type> ::= Dt <expression> # decltype of an id-expression or # class member access <type> ::= DT <expression> # decltype of an expression + <type> ::= Dn # decltype of nullptr TYPE is a type node. */ @@ -1932,6 +1933,10 @@ write_type (tree type) write_char ('E'); break; + case NULLPTR_TYPE: + write_string ("Dn"); + break; + case TYPEOF_TYPE: sorry ("mangling typeof, use decltype instead"); break; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 5586bf7..ebc689b 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4859,6 +4859,7 @@ arg_assoc_type (struct arg_lookup *k, tree type) case BOOLEAN_TYPE: case FIXED_POINT_TYPE: case DECLTYPE_TYPE: + case NULLPTR_TYPE: return false; case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c3e27e5..05b5b66 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3368,6 +3368,11 @@ cp_parser_primary_expression (cp_parser *parser, cp_lexer_consume_token (parser->lexer); return null_node; + /* The `nullptr' literal. */ + case RID_NULLPTR: + cp_lexer_consume_token (parser->lexer); + return nullptr_node; + /* Recognize the `this' keyword. */ case RID_THIS: cp_lexer_consume_token (parser->lexer); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 6f40653..9a7faec 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1044,6 +1044,7 @@ typeinfo_in_lib_p (tree type) case BOOLEAN_TYPE: case REAL_TYPE: case VOID_TYPE: + case NULLPTR_TYPE: return true; default: @@ -1449,6 +1450,9 @@ create_tinfo_types (void) 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[] = { &void_type_node, @@ -1461,6 +1465,7 @@ emit_support_tinfos (void) &long_long_integer_type_node, &long_long_unsigned_type_node, &float_type_node, &double_type_node, &long_double_type_node, &dfloat32_type_node, &dfloat64_type_node, &dfloat128_type_node, + &nullptr_type_node, 0 }; int ix; @@ -1477,6 +1482,7 @@ emit_support_tinfos (void) if (!dtor || DECL_EXTERNAL (dtor)) return; doing_runtime = 1; + nullptr_type_node = TREE_TYPE (nullptr_node); for (ix = 0; fundamentals[ix]; ix++) { tree bltn = *fundamentals[ix]; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index c601539..61d5f22 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3993,6 +3993,9 @@ cp_build_binary_op (location_t location, } 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) { result_type = type0; @@ -4192,12 +4195,13 @@ cp_build_binary_op (location_t location, else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) result_type = composite_pointer_type (type0, type1, op0, op1, CPO_COMPARISON, complain); - else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST - && integer_zerop (op1)) + else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1)) result_type = type0; - else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST - && integer_zerop (op0)) + else if (code1 == POINTER_TYPE && null_ptr_cst_p (op0)) 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) { result_type = type0; @@ -6020,8 +6024,11 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, /* [expr.reinterpret.cast] A pointer can be converted to any integral type large enough to - hold it. */ - if (CP_INTEGRAL_TYPE_P (type) && TYPE_PTR_P (intype)) + hold it. ... A value of type std::nullptr_t can be converted to + 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)) { @@ -6031,6 +6038,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, else return error_mark_node; } + if (TREE_CODE (intype) == NULLPTR_TYPE) + return build_int_cst (type, 0); } /* [expr.reinterpret.cast] A value of integral or enumeration type can be explicitly diff --git a/gcc/dbxout.c b/gcc/dbxout.c index a314e7b..bce5703 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -1867,6 +1867,7 @@ dbxout_type (tree type, int full) { case VOID_TYPE: case LANG_TYPE: + case NULLPTR_TYPE: /* For a void type, just define it as itself; i.e., "5=5". This makes us consider it defined without saying what it is. The debugger will make it diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 416f75a..66ac5eb 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -12108,6 +12108,7 @@ is_base_type (tree type) case ENUMERAL_TYPE: case FUNCTION_TYPE: case METHOD_TYPE: + case NULLPTR_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: @@ -19171,6 +19172,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, when appropriate. */ 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 INTEGER_TYPE: case REAL_TYPE: diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index dfd38cc..47883e2 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -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 though there is no technical reason for this in gfortran. See Fortran 2003, Section 12.4.1.6 item (7)+(8). */ - tree present, nullptr, type; + tree present, null_ptr, type; if (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, fold_convert (type, null_pointer_node)); type = TREE_TYPE (parmse.expr); - nullptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr, - fold_convert (type, null_pointer_node)); + null_ptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr, + fold_convert (type, null_pointer_node)); cond = fold_build2 (TRUTH_ORIF_EXPR, boolean_type_node, - present, nullptr); + present, null_ptr); } else { diff --git a/gcc/sdbout.c b/gcc/sdbout.c index 87a00b4..6a771f4 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -493,6 +493,7 @@ plain_type_1 (tree type, int level) switch (TREE_CODE (type)) { case VOID_TYPE: + case NULLPTR_TYPE: return T_VOID; case BOOLEAN_TYPE: case INTEGER_TYPE: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 21fec66..8375faf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> PR c++/40406 diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr01.C b/gcc/testsuite/g++.dg/cpp0x/nullptr01.C new file mode 100644 index 0000000..8de877b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr01.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr02.C b/gcc/testsuite/g++.dg/cpp0x/nullptr02.C new file mode 100644 index 0000000..2272152 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr02.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr03.C b/gcc/testsuite/g++.dg/cpp0x/nullptr03.C new file mode 100644 index 0000000..1c9e521 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr03.C @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +// Test assignment to int + +const int n = nullptr; // { dg-error "cannot convert " } diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr04.C b/gcc/testsuite/g++.dg/cpp0x/nullptr04.C new file mode 100644 index 0000000..f092b70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr04.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr05.C b/gcc/testsuite/g++.dg/cpp0x/nullptr05.C new file mode 100644 index 0000000..7c3f8b70 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr05.C @@ -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; diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr06.C b/gcc/testsuite/g++.dg/cpp0x/nullptr06.C new file mode 100644 index 0000000..5dea1fb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr06.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr07.C b/gcc/testsuite/g++.dg/cpp0x/nullptr07.C new file mode 100644 index 0000000..cebed88 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr07.C @@ -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 " } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr08.C b/gcc/testsuite/g++.dg/cpp0x/nullptr08.C new file mode 100644 index 0000000..d7d9169 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr08.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr09.C b/gcc/testsuite/g++.dg/cpp0x/nullptr09.C new file mode 100644 index 0000000..a42821c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr09.C @@ -0,0 +1,9 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +// Test compare to literal 0 + +void fun() +{ + if( nullptr == 0 ); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr10.C b/gcc/testsuite/g++.dg/cpp0x/nullptr10.C new file mode 100644 index 0000000..cd13186 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr10.C @@ -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 " } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr11.C b/gcc/testsuite/g++.dg/cpp0x/nullptr11.C new file mode 100644 index 0000000..85402a1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr11.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr12.C b/gcc/testsuite/g++.dg/cpp0x/nullptr12.C new file mode 100644 index 0000000..f68652c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr12.C @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +// Test sizeof + +static_assert(sizeof(nullptr) == sizeof(void*), "sizeof(nullptr) is wrong"); diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr13.C b/gcc/testsuite/g++.dg/cpp0x/nullptr13.C new file mode 100644 index 0000000..633e971 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr13.C @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-std=c++0x" } + +// Test typeid + +#include <typeinfo> + +void fun() +{ + typeid(nullptr); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr14.C b/gcc/testsuite/g++.dg/cpp0x/nullptr14.C new file mode 100644 index 0000000..0493bcc --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr14.C @@ -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)); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr15.C b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C new file mode 100644 index 0000000..4572c53 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C @@ -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)); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr16.C b/gcc/testsuite/g++.dg/cpp0x/nullptr16.C new file mode 100644 index 0000000..7561b21 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr16.C @@ -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)); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr17.C b/gcc/testsuite/g++.dg/cpp0x/nullptr17.C new file mode 100644 index 0000000..acedbae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr17.C @@ -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)); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr18.C b/gcc/testsuite/g++.dg/cpp0x/nullptr18.C new file mode 100644 index 0000000..192b646 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr18.C @@ -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)); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr19.C b/gcc/testsuite/g++.dg/cpp0x/nullptr19.C new file mode 100644 index 0000000..7eb00bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr19.C @@ -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" } */ +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr20.C b/gcc/testsuite/g++.dg/cpp0x/nullptr20.C new file mode 100644 index 0000000..b7457ca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr20.C @@ -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; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr21.C b/gcc/testsuite/g++.dg/cpp0x/nullptr21.C new file mode 100644 index 0000000..84c34dd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr21.C @@ -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" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr22.C b/gcc/testsuite/g++.dg/cpp0x/nullptr22.C new file mode 100644 index 0000000..13cb8e3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nullptr22.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C b/gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C index 2b84c93..5ad9b61 100644 --- a/gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C +++ b/gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C @@ -1,7 +1,9 @@ // { dg-options "-std=gnu++98 -Wc++0x-compat" } int static_assert; // { dg-warning "will become a keyword" } +int nullptr; // { dg-warning "will become a keyword" } void foo() { static_assert = 5; + nullptr = 5; } diff --git a/gcc/testsuite/g++.dg/debug/nullptr01.C b/gcc/testsuite/g++.dg/debug/nullptr01.C new file mode 100644 index 0000000..ab08588 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/nullptr01.C @@ -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_" } } diff --git a/gcc/testsuite/gcc.dg/Wcxx-compat-2.c b/gcc/testsuite/gcc.dg/Wcxx-compat-2.c index 14edc1a..4578bec 100644 --- a/gcc/testsuite/gcc.dg/Wcxx-compat-2.c +++ b/gcc/testsuite/gcc.dg/Wcxx-compat-2.c @@ -7,6 +7,7 @@ int char16_t; /* { dg-warning "5:keyword" } */ int char32_t; /* { dg-warning "5:keyword" } */ int class; /* { dg-warning "5:keyword" } */ int const_cast; /* { dg-warning "5:keyword" } */ +int constexpr; /* { dg-warning "5:keyword" } */ int decltype; /* { dg-warning "5:keyword" } */ int delete; /* { 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 namespace; /* { dg-warning "5:keyword" } */ int new; /* { dg-warning "5:keyword" } */ +int nullptr; /* { dg-warning "5:keyword" } */ int operator; /* { dg-warning "5:keyword" } */ int private; /* { dg-warning "5:keyword" } */ int protected; /* { dg-warning "5:keyword" } */ |