This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: [C++0x] nullptr
- From: Magnus Fromreide <magfr at lysator dot liu dot se>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org, libstdc++ at gcc dot gnu dot org
- Date: Mon, 03 May 2010 01:17:01 +0200
- Subject: Re: [C++0x] nullptr
- References: <1268546192.2028.32.camel@sara.home> <4BA46E77.6080507@redhat.com> <1269813166.2249.8.camel@sara.home> <4BB12B74.80703@redhat.com> <4BDD0915.2020301@redhat.com>
(libstdc++-folks, there is a library patch in here that I would like to
get reviewed if possible)
On Sun, 2010-05-02 at 01:09 -0400, Jason Merrill wrote:
> On 03/29/2010 06:36 PM, Jason Merrill wrote:
> > On 03/28/2010 05:52 PM, Magnus Fromreide wrote:
> >> + else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
> >> + result_type = TREE_TYPE (nullptr_node);
> >
> > It seems like this ought to make sure that one of the operands is
> > non-integral.
> >
> >> + add_name_attribute(type_die, "decltype(nullptr)");
> >
> > Missing space.
> >
> > Other than that, just need to fix the other debugging backends to treat
> > NULLPTR_TYPE like integer_type_node and the compiler/libiberty changes
> > will be ready for 4.6.
>
> Are you still working on this,
Very slowly. I found another bug in my handling of variadic arguments so
I added testcase nullptr22 and some small changes to cp/call.c for that
as well as the formatting fixes.
> or would you like me to make the necessary changes to the debugging backends?
Yes, please.
/MF
Index: gcc/testsuite/g++.dg/cpp0x/nullptr22.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr22.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr22.C (revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr05.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr05.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr05.C (revision 0)
@@ -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;
Index: gcc/testsuite/g++.dg/cpp0x/nullptr14.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr14.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr14.C (revision 0)
@@ -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));
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr06.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr06.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr06.C (revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr15.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr15.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr15.C (revision 0)
@@ -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));
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr07.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr07.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr07.C (revision 0)
@@ -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 " }
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr16.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr16.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr16.C (revision 0)
@@ -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));
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr08.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr08.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr08.C (revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr17.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr17.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr17.C (revision 0)
@@ -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));
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr01.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr01.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr01.C (revision 0)
@@ -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;
Index: gcc/testsuite/g++.dg/cpp0x/nullptr09.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr09.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr09.C (revision 0)
@@ -0,0 +1,9 @@
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+// Test compare to literal 0
+
+void fun()
+{
+ if( nullptr == 0 );
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr10.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr10.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr10.C (revision 0)
@@ -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 " }
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr18.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr18.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr18.C (revision 0)
@@ -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));
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr02.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr02.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr02.C (revision 0)
@@ -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;
Index: gcc/testsuite/g++.dg/cpp0x/nullptr11.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr11.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr11.C (revision 0)
@@ -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);
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr19.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr19.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr19.C (revision 0)
@@ -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" } */
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr20.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr20.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr20.C (revision 0)
@@ -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;
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr03.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr03.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr03.C (revision 0)
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+// Test assignment to int
+
+const int n = nullptr; // { dg-error "cannot convert " }
Index: gcc/testsuite/g++.dg/cpp0x/nullptr12.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr12.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr12.C (revision 0)
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+// Test sizeof
+
+static_assert(sizeof(nullptr) == sizeof(void*), "sizeof(nullptr) is wrong");
Index: gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C (revision 158982)
+++ gcc/testsuite/g++.dg/cpp0x/warn_cxx0x.C (working copy)
@@ -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;
}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr21.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr21.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr21.C (revision 0)
@@ -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" }
+}
Index: gcc/testsuite/g++.dg/cpp0x/nullptr04.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr04.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr04.C (revision 0)
@@ -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;
Index: gcc/testsuite/g++.dg/cpp0x/nullptr13.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/nullptr13.C (revision 0)
+++ gcc/testsuite/g++.dg/cpp0x/nullptr13.C (revision 0)
@@ -0,0 +1,11 @@
+// { dg-do compile }
+// { dg-options "-std=c++0x" }
+
+// Test typeid
+
+#include <typeinfo>
+
+void fun()
+{
+ typeid(nullptr);
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 158982)
+++ gcc/cp/typeck.c (working copy)
@@ -3983,6 +3983,8 @@
}
result_type = type1;
}
+ else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
+ result_type = TREE_TYPE (nullptr_node);
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
@@ -4181,11 +4183,13 @@
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))
+ && null_ptr_cst_p (op1))
result_type = type0;
else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
- && integer_zerop (op0))
+ && null_ptr_cst_p (op0))
result_type = type1;
+ else if (null_ptr_cst_p (op0) && null_ptr_cst_p (op1))
+ result_type = TREE_TYPE (nullptr_node);
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
@@ -6004,8 +6008,11 @@
/* [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))
{
@@ -6015,6 +6022,8 @@
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
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 158982)
+++ gcc/cp/decl.c (working copy)
@@ -3501,6 +3501,17 @@
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
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c (revision 158982)
+++ gcc/cp/error.c (working copy)
@@ -475,6 +475,10 @@
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 @@
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 @@
case DECLTYPE_TYPE:
case TYPE_PACK_EXPANSION:
case FIXED_POINT_TYPE:
+ case NULLPTR_TYPE:
break;
default:
Index: gcc/cp/cxx-pretty-print.c
===================================================================
--- gcc/cp/cxx-pretty-print.c (revision 158982)
+++ gcc/cp/cxx-pretty-print.c (working copy)
@@ -339,6 +339,16 @@
}
break;
+ case INTEGER_CST:
+ {
+ tree type = TREE_TYPE (t);
+ if (type == TREE_TYPE (nullptr_node))
+ pp_string (pp, "nullptr");
+ else
+ pp_c_constant (pp_c_base (pp), t);
+ }
+ break;
+
default:
pp_c_constant (pp_c_base (pp), t);
break;
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 158982)
+++ gcc/cp/parser.c (working copy)
@@ -3368,6 +3368,11 @@
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);
Index: gcc/cp/cp-tree.def
===================================================================
--- gcc/cp/cp-tree.def (revision 158982)
+++ gcc/cp/cp-tree.def (working copy)
@@ -449,6 +449,9 @@
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, "std::nullptr_t", tcc_type, 0)
+
/*
Local variables:
mode:c
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c (revision 158982)
+++ gcc/cp/call.c (working copy)
@@ -460,9 +460,11 @@
/* [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 @@
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 @@
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;
}
@@ -5189,6 +5199,8 @@
< 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);
@@ -6794,9 +6806,8 @@
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. */
Index: gcc/cp/cvt.c
===================================================================
--- gcc/cp/cvt.c (revision 158982)
+++ gcc/cp/cvt.c (working copy)
@@ -703,6 +703,8 @@
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)
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c (revision 158982)
+++ gcc/cp/mangle.c (working copy)
@@ -1759,6 +1759,7 @@
<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_char ('E');
break;
+ case NULLPTR_TYPE:
+ write_string ("Dn");
+ break;
+
case TYPEOF_TYPE:
sorry ("mangling typeof, use decltype instead");
break;
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 158982)
+++ gcc/cp/cp-tree.h (working copy)
@@ -775,6 +775,8 @@
CPTI_KEYED_CLASSES,
+ CPTI_NULLPTR,
+
CPTI_MAX
};
@@ -809,6 +811,7 @@
#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 @@
/* [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 @@
|| 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
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c (revision 158982)
+++ gcc/cp/name-lookup.c (working copy)
@@ -4859,6 +4859,7 @@
case BOOLEAN_TYPE:
case FIXED_POINT_TYPE:
case DECLTYPE_TYPE:
+ case NULLPTR_TYPE:
return false;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c (revision 158982)
+++ gcc/dwarf2out.c (working copy)
@@ -12108,6 +12108,7 @@
case ENUMERAL_TYPE:
case FUNCTION_TYPE:
case METHOD_TYPE:
+ case NULLPTR_TYPE:
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
@@ -19157,6 +19158,18 @@
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:
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c (revision 158982)
+++ gcc/c-common.c (working copy)
@@ -660,6 +660,7 @@
{ "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 },
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h (revision 158982)
+++ gcc/c-common.h (working copy)
@@ -114,7 +114,7 @@
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 @@
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,
Index: libiberty/cp-demangle.c
===================================================================
--- libiberty/cp-demangle.c (revision 158982)
+++ libiberty/cp-demangle.c (working copy)
@@ -1987,6 +1987,8 @@
/* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT },
/* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT },
/* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT },
+ /* 32 */ { NL ("std::nullptr_t"), NL ("std::nullptr_t"),
+ D_PRINT_DEFAULT },
};
CP_STATIC_IF_GLIBCPP_V3
@@ -2221,6 +2223,12 @@
ret = d_vector_type (di);
break;
+ case 'n':
+ /* std::nullptr_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
default:
return NULL;
}
Index: libiberty/cp-demangle.h
===================================================================
--- libiberty/cp-demangle.h (revision 158982)
+++ libiberty/cp-demangle.h (working copy)
@@ -147,7 +147,7 @@
extern const struct demangle_operator_info cplus_demangle_operators[];
#endif
-#define D_BUILTIN_TYPE_COUNT (32)
+#define D_BUILTIN_TYPE_COUNT (33)
CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info
Index: libstdc++-v3/include/std/functional
===================================================================
--- libstdc++-v3/include/std/functional (revision 158982)
+++ libstdc++-v3/include/std/functional (working copy)
@@ -1394,11 +1394,10 @@
class bad_function_call : public std::exception { };
/**
- * The integral constant expression 0 can be converted into a
- * pointer to this type. It is used by the function template to
- * accept NULL pointers.
+ * The integral constant expression 0 can be converted into this
+ * type. It is used by the function template to accept NULL pointers.
*/
- struct _M_clear_type;
+ typedef decltype(nullptr) __nullptr_t;
/**
* Trait identifying "location-invariant" types, meaning that the
@@ -1810,7 +1809,7 @@
* @brief Default construct creates an empty function call wrapper.
* @post @c !(bool)*this
*/
- function(_M_clear_type*) : _Function_base() { }
+ function(__nullptr_t) : _Function_base() { }
/**
* @brief %Function copy constructor.
@@ -1903,7 +1902,7 @@
* The target of @c *this is deallocated, leaving it empty.
*/
function&
- operator=(_M_clear_type*)
+ operator=(__nullptr_t)
{
if (_M_manager)
{
@@ -2156,13 +2155,13 @@
*/
template<typename _Res, typename... _Args>
inline bool
- operator==(const function<_Res(_Args...)>& __f, _M_clear_type*)
+ operator==(const function<_Res(_Args...)>& __f, __nullptr_t)
{ return !static_cast<bool>(__f); }
/// @overload
template<typename _Res, typename... _Args>
inline bool
- operator==(_M_clear_type*, const function<_Res(_Args...)>& __f)
+ operator==(__nullptr_t, const function<_Res(_Args...)>& __f)
{ return !static_cast<bool>(__f); }
/**
@@ -2174,13 +2173,13 @@
*/
template<typename _Res, typename... _Args>
inline bool
- operator!=(const function<_Res(_Args...)>& __f, _M_clear_type*)
+ operator!=(const function<_Res(_Args...)>& __f, __nullptr_t)
{ return static_cast<bool>(__f); }
/// @overload
template<typename _Res, typename... _Args>
inline bool
- operator!=(_M_clear_type*, const function<_Res(_Args...)>& __f)
+ operator!=(__nullptr_t, const function<_Res(_Args...)>& __f)
{ return static_cast<bool>(__f); }
// [20.7.15.2.7] specialized algorithms
Index: libstdc++-v3/include/bits/shared_ptr.h
===================================================================
--- libstdc++-v3/include/bits/shared_ptr.h (revision 158982)
+++ libstdc++-v3/include/bits/shared_ptr.h (working copy)
@@ -81,6 +81,9 @@
}
+ typedef decltype(nullptr) __nullptr_t;
+
+
/**
* @brief A smart pointer with reference-counted copy semantics.
*
@@ -123,6 +126,23 @@
shared_ptr(_Tp1* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, __d) { }
/**
+ * @brief Construct an empty %shared_ptr that owns the
+ * deleter @a __d.
+ * @param __p A null pointer constant.
+ * @param __d A deleter.
+ * @post use_count() == 1 && get() == __p
+ * @throw std::bad_alloc, in which case @a __d(__p) is called.
+ *
+ * Requirements: _Deleter's copy constructor and destructor must
+ * not throw
+ *
+ * __shared_ptr will release __p by calling __d(__p)
+ */
+ template<typename _Tp1, typename _Deleter>
+ shared_ptr(__nullptr_t __p, _Deleter __d)
+ : __shared_ptr<_Tp>(__p, __d) { }
+
+ /**
* @brief Construct a %shared_ptr that owns the pointer @a __p
* and the deleter @a __d.
* @param __p A pointer.
@@ -141,6 +161,25 @@
shared_ptr(_Tp1* __p, _Deleter __d, const _Alloc& __a)
: __shared_ptr<_Tp>(__p, __d, __a) { }
+ /**
+ * @brief Construct a %shared_ptr that owns the pointer @a __p
+ * and the deleter @a __d.
+ * @param __p A null pointer constant.
+ * @param __d A deleter.
+ * @param __a An allocator.
+ * @post use_count() == 1 && get() == __p
+ * @throw std::bad_alloc, in which case @a __d(__p) is called.
+ *
+ * Requirements: _Deleter's copy constructor and destructor must
+ * not throw _Alloc's copy constructor and destructor must not
+ * throw.
+ *
+ * __shared_ptr will release __p by calling __d(__p)
+ */
+ template<typename _Tp1, typename _Deleter, typename _Alloc>
+ shared_ptr(__nullptr_t __p, _Deleter __d, const _Alloc& __a)
+ : __shared_ptr<_Tp>(__p, __d, __a) { }
+
// Aliasing constructor
/**
@@ -212,7 +251,15 @@
shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r)) { }
+ /**
+ * @brief Construct an empty %shared_ptr.
+ * @param __p A null pointer constant.
+ * @post use_count() == 1 && get() == nullptr
+ */
template<typename _Tp1>
+ shared_ptr(nullptr_t __p) : __shared_ptr<_Tp>() { }
+
+ template<typename _Tp1>
shared_ptr&
operator=(const shared_ptr<_Tp1>& __r) // never throws
{
Index: libstdc++-v3/include/bits/unique_ptr.h
===================================================================
--- libstdc++-v3/include/bits/unique_ptr.h (revision 158982)
+++ libstdc++-v3/include/bits/unique_ptr.h (working copy)
@@ -76,12 +76,15 @@
}
};
+
+ typedef decltype(nullptr) __nullptr_t;
+
+
/// 20.7.12.2 unique_ptr for single objects.
template <typename _Tp, typename _Tp_Deleter = default_delete<_Tp> >
class unique_ptr
{
typedef std::tuple<_Tp*, _Tp_Deleter> __tuple_type;
- typedef _Tp* unique_ptr::* __unspecified_pointer_type;
// use SFINAE to determine whether _Del::pointer exists
class _Pointer
@@ -126,6 +129,8 @@
{ static_assert(!std::is_reference<deleter_type>::value,
"rvalue deleter bound to reference"); }
+ unique_ptr(__nullptr_t): unique_ptr() { }
+
// Move constructors.
unique_ptr(unique_ptr&& __u)
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
@@ -157,7 +162,7 @@
}
unique_ptr&
- operator=(__unspecified_pointer_type)
+ operator=(__nullptr_t)
{
reset();
return *this;
@@ -234,7 +239,7 @@
class unique_ptr<_Tp[], _Tp_Deleter>
{
typedef std::tuple<_Tp*, _Tp_Deleter> __tuple_type;
- typedef _Tp* unique_ptr::* __unspecified_pointer_type;
+ typedef decltype(nullptr)* __nullptr_t;
public:
typedef _Tp* pointer;
@@ -264,6 +269,8 @@
{ static_assert(!std::is_reference<deleter_type>::value,
"rvalue deleter bound to reference"); }
+ unique_ptr(__nullptr_t): unique_ptr() { }
+
// Move constructors.
unique_ptr(unique_ptr&& __u)
: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) { }
@@ -295,7 +302,7 @@
}
unique_ptr&
- operator=(__unspecified_pointer_type)
+ operator=(__nullptr_t)
{
reset();
return *this;
@@ -342,6 +349,15 @@
get_deleter()(__p);
}
+ void
+ reset(__nullptr_t)
+ {
+ pointer __p = get();
+ std::get<0>(_M_t) = pointer();
+ if (__p != pointer())
+ get_deleter()(__p);
+ }
+
// DR 821.
template<typename _Up>
void reset(_Up) = delete;
Index: libstdc++-v3/include/c_global/cstddef
===================================================================
--- libstdc++-v3/include/c_global/cstddef (revision 158982)
+++ libstdc++-v3/include/c_global/cstddef (working copy)
@@ -51,6 +51,10 @@
using ::ptrdiff_t;
using ::size_t;
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ typedef decltype(nullptr) nullptr_t;
+#endif
+
_GLIBCXX_END_NAMESPACE
#endif