This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [C++0x] nullptr


On Sat, 2010-03-20 at 02:43 -0400, Jason Merrill wrote: 
> On 03/14/2010 12:56 AM, Magnus Fromreide wrote:
> > First, I am not certain about how
> >
> >    foo(char*)
> >    foo(decltype(nullptr))
> >    void f() { foo(0); }
> >
> > should be handled - Looking at n3035 I think i should be ambiguous but
> > that feels very odd. If someone could help me understand this I would be
> > happy.
> 
> Conversion from 0 to nullptr_t is a pointer conversion, just as 
> conversion to char*.

Ok, so the example should be ambiguous.

> The goal of introducing nullptr is to allow us to use something better
> than 0 as the argument.

Yes, but I think there might be some legacy code about that use 0.

The problem is when you compare it to

template <class T> void foo(T*); // #1
void foo(nullptr_t); // #2

where nullptr_t is a better match for foo(0).

Adding

void foo(const char*); // #3

makes the call ambiguous, template specialization is not viable as this
is function templates so how do I achieve this effect? I think the
overload resolution should be

     1. int 
     2. nullptr_t 
     3. any pointer type

but that it probably better discussed over at comp.std.c++.

> > Secondly, I have choosen to call the type that results from
> > decltype(nullptr) 'std::nullptr_t' in order to make the error messages
> > more readable - I am uncertain of this decision though, would it be
> > better to call it 'decltype(nullptr)'?
> 
> I think use std::nullptr_t.

:-)

> > Thirdly, in the test suite nullptr19.C fails due to excess errors, I do
> > not know how to make it not fail as I think it looks like I have told
> > deja-gnus about all the errors that I expect.
> 
> > +//  type_equal<nullptr_t>(k(__null)); /* { dg-error "is ambiguous" } */
> 
> Is this line supposed to be commented out?  It won't get an error that way.

No. I found out that the problem was that each pattern only match once
so I had to add one more dg-message as follows

char* k(char*);/* { dg-message "note" } { dg-message "note" } */

Thanks to you and Andreas Schwab for explaining deja-gnus to me.

> > Index: gcc/testsuite/g++.dg/cpp0x/nullptr09.C
> > +  if( nullptr == 0 );  // { dg-error "invalid operands of types " }
> 
> This is well-formed; the composite pointer type here is nullptr_t, which 
> will be clearer in the forthcoming FCD.  See
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#963

Ok. I must have missed this.

> > +// Test aritmetic operations
> 
> "arithmetic"
> 
> > +      else if (code0 == NULLPTR_TYPE && code1 == NULLPTR_TYPE)
> > +        {
> > +          if (code == EQ_EXPR)
> > +            result_type = type1;
> > +          else
> > +            result_type = type0;
> > +        }
> 
> It seems that you expect type1 and type0 to encode boolean true and 
> false, which they don't.  Both of them will be nullptr_t.  And the same 
> comment for the next hunk.

You are right. I have changed result_type to be TREE_TYPE (nullptr) as
that is the type that should be used for the comparisions.

> > +      if (TREE_CODE (intype) == NULLPTR_TYPE)
> > +        return build_int_cst (type, 0);
> 
> Why not fall through to cp_convert in this case?

cp_convert in effect performs static_cast<target>(source), in this case
that would be static_cast<integer-type>(nullptr) but that conversion
isn't valid except when integer-type is bool.

Removing this part triggers the following unexpected errors in the test
suite:

/usr/local/src/gcc/trunk/gcc/testsuite/g++.dg/cpp0x/nullptr04.C:8:55:
error: aggregate value used where an integer was expected
/usr/local/src/gcc/trunk/gcc/testsuite/g++.dg/cpp0x/nullptr04.C:9:31:
error: aggregate value used where an integer was expected

> 
... 
> 
> > Fourthly, the patch only adds support for nullptr on ELF - I do not know
> > neither how to encode it nor in what file to do it on other platforms.
> > For ELF i used the proposed extension from
> > http://www.codesourcery.com/archives/cxx-abi-dev/msg02159.html as that
> > seemed uncontroversial.
> > Support for all other object formats is completely missing and so
> > triggers ICE's.
> 
> Mangling is independent of object file format, the code you add to 
> mangle.c should cover all of them.

Does GCC mangle the same on all platforms and ignore the mangling of the
default platform compiler?

Anyway, in that case it works so that is good.

> > Fifthly, the patch don't add support for any debugging format. I have
> > seen http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Null_pointer
> > but failed to wrap my head around dwarf2out.c. The patch add enough
> > support to not trigger an ICE but this is very half baked and so needs
> > to be fixed.
> > Support for all other debugging formats is completely missing and so
> > triggers ICE's.
> 
> > +++ gcc/dwarf2out.c	(working copy)
> > @@ -12019,6 +12019,7 @@
> >      case ENUMERAL_TYPE:
> >      case FUNCTION_TYPE:
> >      case METHOD_TYPE:
> > +    case NULLPTR_TYPE:
> 
> Hmm, interesting that this compiles, given that NULLPTR_TYPE is a front 
> end tree code.  I hadn't previously noticed the change to make all tree 
> codes available from tree.h.
> 
> I think you just want something like
> 
> dw_die_ref die = new_die (DW_TAG_unspecified_type, comp_unit_die, type);
> add_name_attribute (die, "decltype(nullptr)");

Yes, that manages to output the tag into the debug information but the
tags are disconnected and repeated so something must still be wrong in
that part of code.
More debug studies gives that the important missing part is 

equate_type_number_to_die (type, type_die);

> I'm not sure how gdb will deal with either decltype(nullptr) or 
> std::nullptr_t as names, it might have problems.

Well, that is a problem for the future - right now possibly missing gdb
support is a not an issue.

Now the missing parts are a lot smaller - there is no support for output
of nullptr's (as opposed to nullptr_t's) but i do not see how to
generate a nullptr either and there are still a bunch of missing debug
output formats.

/MF
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 157783)
+++ 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 157783)
+++ gcc/cp/typeck.c	(working copy)
@@ -3957,6 +3957,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;
@@ -4155,11 +4157,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;
@@ -5978,8 +5982,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))
         {
@@ -5989,6 +5996,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 157783)
+++ gcc/cp/decl.c	(working copy)
@@ -3498,6 +3498,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 157783)
+++ 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 157783)
+++ 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 157783)
+++ gcc/cp/parser.c	(working copy)
@@ -3367,6 +3367,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/call.c
===================================================================
--- gcc/cp/call.c	(revision 157783)
+++ 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))
     {
@@ -772,7 +774,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)
@@ -907,17 +914,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;
 	}
@@ -6786,9 +6796,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/cp-tree.def
===================================================================
--- gcc/cp/cp-tree.def	(revision 157783)
+++ 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/cvt.c
===================================================================
--- gcc/cp/cvt.c	(revision 157783)
+++ gcc/cp/cvt.c	(working copy)
@@ -701,6 +701,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 157783)
+++ gcc/cp/mangle.c	(working copy)
@@ -1760,6 +1760,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.  */
 
@@ -1933,6 +1934,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 157783)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -778,6 +778,8 @@
 
     CPTI_KEYED_CLASSES,
 
+    CPTI_NULLPTR,
+
     CPTI_MAX
 };
 
@@ -812,6 +814,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.  */
@@ -2995,8 +2998,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)			\
@@ -3004,7 +3008,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 157783)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -4854,6 +4854,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 157783)
+++ gcc/dwarf2out.c	(working copy)
@@ -12031,6 +12031,7 @@
     case ENUMERAL_TYPE:
     case FUNCTION_TYPE:
     case METHOD_TYPE:
+    case NULLPTR_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
     case OFFSET_TYPE:
@@ -19059,6 +19060,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 157783)
+++ gcc/c-common.c	(working copy)
@@ -657,6 +657,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 157783)
+++ 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 157783)
+++ 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 157783)
+++ 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 157783)
+++ libstdc++-v3/include/std/functional	(working copy)
@@ -1417,11 +1417,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
@@ -1833,7 +1832,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.
@@ -1926,7 +1925,7 @@
        *  The target of @c *this is deallocated, leaving it empty.
        */
       function&
-      operator=(_M_clear_type*)
+      operator=(__nullptr_t)
       {
         if (_M_manager)
 	  {
@@ -2179,13 +2178,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); }
 
   /**
@@ -2197,13 +2196,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 157783)
+++ 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 157783)
+++ 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;
 
     public:
       typedef _Tp*               pointer;
@@ -111,6 +114,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())) { }
@@ -142,7 +147,7 @@
         }
 
       unique_ptr&
-      operator=(__unspecified_pointer_type) 
+      operator=(__nullptr_t)
       {
 	reset();
 	return *this;
@@ -219,7 +224,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;
@@ -249,6 +254,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())) { }
@@ -280,7 +287,7 @@
         }
 
       unique_ptr&
-      operator=(__unspecified_pointer_type)
+      operator=(__nullptr_t)
       {
 	reset();
 	return *this;
@@ -327,6 +334,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 157783)
+++ 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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]