This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ 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 05/02/2010 07:17 PM, Magnus Fromreide wrote:
or would you like me to make the necessary changes to the debugging backends?

Yes, please.

I made those changes and a few other tweaks that I noticed while preparing the patch to go in:


* I think my choice of std::nullptr_t was wrong before, so I changed it to decltype(nullptr).
* I put typeid(decltype(nullptr)) into the runtime library.
* I added some tests for debugging, mangling and demangling.
* I fixed an instance of "nullptr" in the fortran front end.
* And a few other minor tweaks.


Attached are the diffs relative to your patches (nullptr-changes.patch) and the full patch I'm committing (nullptr-full.patch).

Thanks a lot for your work on this!

Tested x86_64-pc-linux-gnu, applying to trunk. Now you only need to deal with the library folks. :)

Incidentally, library folks: does my change to gnu.ver look right? I noticed that the stuff I put there before was redundant.
commit a29f471a6c8321c130ecda7182199add1d544945
Author: Jason Merrill <jason@redhat.com>
Date:   Tue May 4 17:24:35 2010 -0400

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

diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def
index 636bc74..c3e8208 100644
--- a/gcc/cp/cp-tree.def
+++ b/gcc/cp/cp-tree.def
@@ -450,7 +450,7 @@ DEFTREECODE (DECLTYPE_TYPE, "decltype_type", tcc_type, 0)
 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)
+DEFTREECODE (NULLPTR_TYPE, "decltype(nullptr)", tcc_type, 0)
 
 /*
 Local variables:
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 6d95072..55def21 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -340,14 +340,12 @@ pp_cxx_constant (cxx_pretty_printer *pp, tree t)
       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;
+      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);
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 b62b164..61d5f22 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3994,6 +3994,7 @@ 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)
 	{
@@ -4194,13 +4195,12 @@ 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
-	       && null_ptr_cst_p (op1))
+      else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))
 	result_type = type0;
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-	       && null_ptr_cst_p (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)
 	{
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 2f0e83e..66ac5eb 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -19174,11 +19174,11 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
 
     case NULLPTR_TYPE:
       {
-        dw_die_ref type_die = lookup_type_die(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)");
+            add_name_attribute (type_die, "decltype(nullptr)");
             equate_type_number_to_die (type, type_die);
           }
       }
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/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" } */
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index e21f467..6db1f78 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -1987,7 +1987,7 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
   /* 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"),
+  /* 32 */ { NL ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
 	     D_PRINT_DEFAULT },
 };
 
@@ -2224,7 +2224,7 @@ cplus_demangle_type (struct d_info *di)
 	  break;
 
         case 'n':
-          /* std::nullptr_t */
+          /* decltype(nullptr) */
 	  ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
 	  di->expansion += ret->u.s_builtin.type->len;
 	  break;
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 672f352..a3331c4 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -3938,6 +3938,9 @@ decltype ((operator+)({parm#1}, {parm#1})) f<A>(A)
 --format=gnu-v3
 _Z1hI1AEDTcldtfp_miEET_
 decltype (({parm#1}.(operator-))()) h<A>(A)
+--format=gnu-v3
+_Z1fDn
+f(decltype(nullptr))
 #
 # Ada (GNAT) tests.
 #
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 1df6499..3552d59 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1307,12 +1307,9 @@ CXXABI_1.3.3 {
 
 CXXABI_1.3.4 {
 
-    # typeinfo for decimal floating point types
-    _ZTID[fde];
-    _ZTIPD[fde];
-    _ZTIPKD[fde];
-    _ZTID[fde];
-    _ZTIPD[fde];
-    _ZTIPKD[fde];
+    # typeinfo for decimal floating point types and decltype(nullptr)
+    _ZTID[fden];
+    _ZTIPD[fden];
+    _ZTIPKD[fden];
 
 } CXXABI_1.3.3;
commit 5ecd9adf3b274045c77c59840ebacbfb03f1e5be
Author: Jason Merrill <jason@redhat.com>
Date:   Tue May 4 17:24:35 2010 -0400

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

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/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/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..7c3f8b7
--- /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" } */
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 98c64db..6db1f78 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -1987,6 +1987,8 @@ cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
   /* 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 ("decltype(nullptr)"),	NL ("decltype(nullptr)"),
+	     D_PRINT_DEFAULT },
 };
 
 CP_STATIC_IF_GLIBCPP_V3
@@ -2221,6 +2223,12 @@ cplus_demangle_type (struct d_info *di)
 	  ret = d_vector_type (di);
 	  break;
 
+        case 'n':
+          /* decltype(nullptr) */
+	  ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+	  di->expansion += ret->u.s_builtin.type->len;
+	  break;
+
 	default:
 	  return NULL;
 	}
diff --git a/libiberty/cp-demangle.h b/libiberty/cp-demangle.h
index aad3743..eac054e 100644
--- a/libiberty/cp-demangle.h
+++ b/libiberty/cp-demangle.h
@@ -147,7 +147,7 @@ struct d_info
 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
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 672f352..a3331c4 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -3938,6 +3938,9 @@ decltype ((operator+)({parm#1}, {parm#1})) f<A>(A)
 --format=gnu-v3
 _Z1hI1AEDTcldtfp_miEET_
 decltype (({parm#1}.(operator-))()) h<A>(A)
+--format=gnu-v3
+_Z1fDn
+f(decltype(nullptr))
 #
 # Ada (GNAT) tests.
 #
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 1df6499..3552d59 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1307,12 +1307,9 @@ CXXABI_1.3.3 {
 
 CXXABI_1.3.4 {
 
-    # typeinfo for decimal floating point types
-    _ZTID[fde];
-    _ZTIPD[fde];
-    _ZTIPKD[fde];
-    _ZTID[fde];
-    _ZTIPD[fde];
-    _ZTIPKD[fde];
+    # typeinfo for decimal floating point types and decltype(nullptr)
+    _ZTID[fden];
+    _ZTIPD[fden];
+    _ZTIPKD[fden];
 
 } CXXABI_1.3.3;

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