diff mbox

C++/libiberty PATCH for many mangling fixes (6057, 48051, 50855, 51322 and more)

Message ID 4F0769D4.2070802@redhat.com
State New
Headers show

Commit Message

Jason Merrill Jan. 6, 2012, 9:38 p.m. UTC
This patch fixes several mangling issues that have been around for a 
while; several things didn't have a defined mangling until recently, and 
others have been adjusted subtly.  The most notable of these is that the 
mangling for a C++11 template argument pack has changed, which affects 
any code that uses variadic templates.

For the moment, only the additions are enabled by default; the changes 
require -fabi-version=6 or =0.  Other changes since -fabi-version=2 have 
been fairly limited in scope, not affecting very much code.  But this is 
a big change, that will require recompilation of pretty much any C++11 
code when it happens.  The question is, should it happen now, or wait 
until a later flag day when we make other changes as well?

We have said that we make no guarantees about backward compatibility in 
C++0x mode, but we still need to decide whether to break it 
incrementally (so that future breakage will be less, and to improve 
compatibility with other compilers) or all at once later on?

Tested x86_64-pc-linux-gnu, applying to trunk.

Comments

Joseph Myers Jan. 6, 2012, 9:57 p.m. UTC | #1
On Fri, 6 Jan 2012, Jason Merrill wrote:

> For the moment, only the additions are enabled by default; the changes require
> -fabi-version=6 or =0.  Other changes since -fabi-version=2 have been fairly
> limited in scope, not affecting very much code.  But this is a big change,
> that will require recompilation of pretty much any C++11 code when it happens.
> The question is, should it happen now, or wait until a later flag day when we
> make other changes as well?

"other changes" might also include moving to libstdc++.so.7 - if there's a 
such an incompatible library ABI change coming up, it would make sense to 
do the compiler ABI changes at the same time.
diff mbox

Patch

commit c712790430099b450bbdcdbda237121893b7b3d2
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 6 09:35:14 2012 -0500

    	* error.c (dump_expr): Print type of CONSTRUCTOR.

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 21d6781..62b47ca 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2194,6 +2194,8 @@  dump_expr (tree t, int flags)
 	}
       else
 	{
+	  if (!BRACE_ENCLOSED_INITIALIZER_P (t))
+	    dump_type (TREE_TYPE (t), 0);
 	  pp_cxx_left_brace (cxx_pp);
 	  dump_expr_init_vec (CONSTRUCTOR_ELTS (t), flags);
 	  pp_cxx_right_brace (cxx_pp);
diff --git a/gcc/testsuite/g++.dg/cpp0x/error7.C b/gcc/testsuite/g++.dg/cpp0x/error7.C
new file mode 100644
index 0000000..0dfbf9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/error7.C
@@ -0,0 +1,10 @@ 
+// Test for printing the type of T{} in error messages.
+// { dg-options -std=c++0x }
+
+template <class T, T t> struct A { };
+template <class T> A<T,T{}> f(T t); // { dg-message "T{}" }
+
+int main()
+{
+  f();				// { dg-error "no match" }
+}

commit 5bebdf16393c8f6ca7b9b2f2cd741919ac25d952
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 6 09:39:03 2012 -0500

    	* mangle.c (mangle_decl): Don't generate mangling aliases
    	for maybe-in-charge [cd]tors.

diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 548998a..e5c2895 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3194,7 +3194,10 @@  mangle_decl (const tree decl)
   tree id = get_mangled_id (decl);
   SET_DECL_ASSEMBLER_NAME (decl, id);
 
-  if (G.need_abi_warning)
+  if (G.need_abi_warning
+      /* Don't do this for a fake symbol we aren't going to emit anyway.  */
+      && !DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
+      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
     {
 #ifdef ASM_OUTPUT_DEF
       /* If the mangling will change in the future, emit an alias with the

commit c427dcbe4bedd0f17df7054d17412960e0cba40c
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 6 09:44:05 2012 -0500

    	* cp-demangle.c (cplus_demangle_type): decltype, pack expansion
    	and vector are substitutable.
    	(cplus_demangle_operators): Sort.

diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 0f1166b..0ed8397 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -1554,7 +1554,8 @@  d_identifier (struct d_info *di, int len)
 /* operator_name ::= many different two character encodings.
                  ::= cv <type>
                  ::= v <digit> <source-name>
-*/
+
+   This list is sorted for binary search.  */
 
 #define NL(s) s, (sizeof s) - 1
 
@@ -1566,6 +1567,8 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "aa", NL ("&&"),        2 },
   { "ad", NL ("&"),         1 },
   { "an", NL ("&"),         2 },
+  { "at", NL ("alignof "),   1 },
+  { "az", NL ("alignof "),   1 },
   { "cl", NL ("()"),        2 },
   { "cm", NL (","),         2 },
   { "co", NL ("~"),         1 },
@@ -1611,8 +1614,6 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "rs", NL (">>"),        2 },
   { "st", NL ("sizeof "),   1 },
   { "sz", NL ("sizeof "),   1 },
-  { "at", NL ("alignof "),   1 },
-  { "az", NL ("alignof "),   1 },
   { NULL, NULL, 0,          0 }
 };
 
@@ -2242,12 +2243,14 @@  cplus_demangle_type (struct d_info *di)
 			     d_expression (di), NULL);
 	  if (ret && d_next_char (di) != 'E')
 	    ret = NULL;
+	  can_subst = 1;
 	  break;
 	  
 	case 'p':
 	  /* Pack expansion.  */
 	  ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
 			     cplus_demangle_type (di), NULL);
+	  can_subst = 1;
 	  break;
 	  
 	case 'f':
@@ -2298,6 +2301,7 @@  cplus_demangle_type (struct d_info *di)
 
 	case 'v':
 	  ret = d_vector_type (di);
+	  can_subst = 1;
 	  break;
 
         case 'n':
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 70abf68..642fe14 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4018,6 +4018,18 @@  K<1, &S::m>::f()
 --format=gnu-v3
 _ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_
 _ZSt10_ConstructI10CellBorderIS0_EEvPT_DpOT0_
+# A pack expansion is substitutable.
+--format=gnu-v3
+_Z1fIJiEiEv1AIJDpT_EET0_S4_
+void f<int, int>(A<int>, int, int)
+# So is decltype.
+--format=gnu-v3
+_Z1fIiiEDTcvT__EET0_S2_
+decltype ((int)()) f<int, int>(int, int)
+# And vector.
+--format=gnu-v3
+_Z1fDv4_iS_
+f(int __vector(4), int __vector(4))
 #
 # Ada (GNAT) tests.
 #

commit f4d29990c578120c19277e4a55e574ad5d384591
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 6 11:13:01 2012 -0500

    	PR c++/6057
    	PR c++/48051
    	PR c++/50855
    	PR c++/51322
    gcc/cp/
    	* mangle.c (write_expression): Support NEW_EXPR, DELETE_EXPR,
    	THROW_EXPR, CONSTRUCTOR, OVERLOAD.  Fix PREINCREMENT_EXPR and
    	PREDECREMENT_EXPR.
    	(write_template_arg): Fix mangling of class-scope functions and
    	argument packs.
    	(mangle_decl): Update suggested -fabi-version argument.
    	* operators.def: Add DOTSTAR_EXPR, REINTERPRET_CAST_EXPR,
    	DYNAMIC_CAST_EXPR; correct CONST_CAST_EXPR, STATIC_CAST_EXPR.
    	* tree.c (dependent_name): No longer static.
    	* cp-tree.h: Declare it.
    	* pt.c (unify): Defer handling of unconverted functions.
    include/
    	* demangle.h (enum demangle_component_type): Add
    	DEMANGLE_COMPONENT_INITIALIZER_LIST, DEMANGLE_COMPONENT_NULLARY.
    libiberty/
    	* cp-demangle.c (d_dump): Handle DEMANGLE_COMPONENT_NULLARY and
    	DEMANGLE_COMPONENT_INITIALIZER_LIST.
    	(d_make_comp): Likewise.  Allow null right arg for
    	DEMANGLE_COMPONENT_TRINARY_ARG2.
    	(cplus_demangle_operators): Adjust new/delete; add .*, :: and throw.
    	(d_template_args, d_template_arg): Handle 'J' for argument packs.
    	(d_exprlist): Add terminator parm.
    	(d_expression, d_print_comp): Handle initializer lists, nullary
    	expressions, prefix/suffix operators, and new.
    	(d_print_subexpr): Avoid parens around DEMANGLE_COMPONENT_QUAL_NAME
    	and DEMANGLE_COMPONENT_INITIALIZER_LIST.
    	* testsuite/demangle-expected: Add tests.

diff --git a/gcc/common.opt b/gcc/common.opt
index 6cfe17a..0544478 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -782,7 +782,10 @@  Driver Undocumented
 ;    function parameters used in other parameters and the return type.
 ;    First selectable in G++ 4.6.
 ;
-; 6: The version of the ABI that doesn't promote scoped enums to int.
+; 6: The version of the ABI that doesn't promote scoped enums to int and
+;    changes the mangling of template argument packs, const/static_cast,
+;    prefix ++ and --, and a class scope function used as a template
+;    argument.
 ;    First selectable in G++ 4.7.
 ;
 ; Additional positive integers will be assigned as new versions of
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6e62bd1..ccad644 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5674,6 +5674,7 @@  extern tree hash_tree_cons			(tree, tree, tree);
 extern tree hash_tree_chain			(tree, tree);
 extern tree build_qualified_name		(tree, tree, tree, bool);
 extern int is_overloaded_fn			(tree);
+extern tree dependent_name			(tree);
 extern tree get_fns				(tree);
 extern tree get_first_fn			(tree);
 extern tree ovl_cons				(tree, tree);
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index e5c2895..f4efa67 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -2646,6 +2646,102 @@  write_expression (tree expr)
       write_expression (TREE_OPERAND (expr, 0));
       write_expression (TREE_OPERAND (expr, 2));
     }
+  else if (code == NEW_EXPR || code == VEC_NEW_EXPR)
+    {
+      /* ::= [gs] nw <expression>* _ <type> E
+	 ::= [gs] nw <expression>* _ <type> <initializer>
+	 ::= [gs] na <expression>* _ <type> E
+	 ::= [gs] na <expression>* _ <type> <initializer>
+	 <initializer> ::= pi <expression>* E  */
+      tree placement = TREE_OPERAND (expr, 0);
+      tree type = TREE_OPERAND (expr, 1);
+      tree nelts = TREE_OPERAND (expr, 2);
+      tree init = TREE_OPERAND (expr, 3);
+      tree t;
+
+      gcc_assert (code == NEW_EXPR);
+      if (TREE_OPERAND (expr, 2))
+	code = VEC_NEW_EXPR;
+
+      if (NEW_EXPR_USE_GLOBAL (expr))
+	write_string ("gs");
+
+      write_string (operator_name_info[(int) code].mangled_name);
+
+      for (t = placement; t; t = TREE_CHAIN (t))
+	write_expression (TREE_VALUE (t));
+
+      write_char ('_');
+
+      if (nelts)
+	{
+	  tree domain;
+	  ++processing_template_decl;
+	  domain = compute_array_index_type (NULL_TREE, nelts,
+					     tf_warning_or_error);
+	  type = build_cplus_array_type (type, domain);
+	  --processing_template_decl;
+	}
+      write_type (type);
+
+      if (init && TREE_CODE (init) == TREE_LIST
+	  && TREE_CODE (TREE_VALUE (init)) == CONSTRUCTOR
+	  && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+	write_expression (TREE_VALUE (init));
+      else
+	{
+	  if (init)
+	    write_string ("pi");
+	  if (init && init != void_zero_node)
+	    for (t = init; t; t = TREE_CHAIN (t))
+	      write_expression (TREE_VALUE (t));
+	  write_char ('E');
+	}
+    }
+  else if (code == DELETE_EXPR || code == VEC_DELETE_EXPR)
+    {
+      gcc_assert (code == DELETE_EXPR);
+      if (DELETE_EXPR_USE_VEC (expr))
+	code = VEC_DELETE_EXPR;
+
+      if (DELETE_EXPR_USE_GLOBAL (expr))
+	write_string ("gs");
+
+      write_string (operator_name_info[(int) code].mangled_name);
+
+      write_expression (TREE_OPERAND (expr, 0));
+    }
+  else if (code == THROW_EXPR)
+    {
+      tree op = TREE_OPERAND (expr, 0);
+      if (op)
+	{
+	  write_string ("tw");
+	  write_expression (op);
+	}
+      else
+	write_string ("tr");
+    }
+  else if (code == CONSTRUCTOR)
+    {
+      VEC(constructor_elt,gc)* elts = CONSTRUCTOR_ELTS (expr);
+      unsigned i; tree val;
+
+      if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+	write_string ("il");
+      else
+	{
+	  write_string ("tl");
+	  write_type (TREE_TYPE (expr));
+	}
+      FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+	write_expression (val);
+      write_char ('E');
+    }
+  else if (dependent_name (expr))
+    {
+      write_unqualified_id (dependent_name (expr));
+    }
   else
     {
       int i, len;
@@ -2688,6 +2784,16 @@  write_expression (tree expr)
 
       /* If it wasn't any of those, recursively expand the expression.  */
       name = operator_name_info[(int) code].mangled_name;
+
+      /* We used to mangle const_cast and static_cast like a C cast.  */
+      if (!abi_version_at_least (6)
+	  && (code == CONST_CAST_EXPR
+	      || code == STATIC_CAST_EXPR))
+	{
+	  name = operator_name_info[CAST_EXPR].mangled_name;
+	  G.need_abi_warning = 1;
+	}
+
       if (name == NULL)
 	{
 	  sorry ("mangling %C", code);
@@ -2734,16 +2840,21 @@  write_expression (tree expr)
 	    }
 	  break;
 
-	  /* FIXME these should have a distinct mangling.  */
+	case DYNAMIC_CAST_EXPR:
+	case REINTERPRET_CAST_EXPR:
 	case STATIC_CAST_EXPR:
 	case CONST_CAST_EXPR:
 	  write_type (TREE_TYPE (expr));
 	  write_expression (TREE_OPERAND (expr, 0));
 	  break;
 
-	case NEW_EXPR:
-	  sorry ("mangling new-expression");
-	  break;
+	case PREINCREMENT_EXPR:
+	case PREDECREMENT_EXPR:
+	  if (abi_version_at_least (6))
+	    write_char ('_');
+	  else
+	    G.need_abi_warning = 1;
+	  /* Fall through.  */
 
 	default:
 	  /* In the middle-end, some expressions have more operands than
@@ -2855,12 +2966,28 @@  write_template_arg (tree node)
 	G.need_abi_warning = 1;
     }
 
+  if (TREE_CODE (node) == BASELINK
+      && !type_unknown_p (node))
+    {
+      if (abi_version_at_least (6))
+	node = BASELINK_FUNCTIONS (node);
+      else
+	/* We wrongly wrapped a class-scope function in X/E.  */
+	G.need_abi_warning = 1;
+    }
+
   if (ARGUMENT_PACK_P (node))
     {
       /* Expand the template argument pack. */
       tree args = ARGUMENT_PACK_ARGS (node);
       int i, length = TREE_VEC_LENGTH (args);
-      write_char ('I');
+      if (abi_version_at_least (6))
+	write_char ('J');
+      else
+	{
+	  write_char ('I');
+	  G.need_abi_warning = 1;
+	}
       for (i = 0; i < length; ++i)
         write_template_arg (TREE_VEC_ELT (args, i));
       write_char ('E');
@@ -3208,8 +3335,8 @@  mangle_decl (const tree decl)
 
       SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
       if (IDENTIFIER_GLOBAL_VALUE (id) != decl)
-	inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=4 (or =0) "
-		"avoids this error with a change in vector mangling");
+	inform (DECL_SOURCE_LOCATION (decl), "-fabi-version=6 (or =0) "
+		"avoids this error with a change in mangling");
 
 #ifdef ASM_OUTPUT_DEF
       save_ver = flag_abi_version;
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index 20d811b..3dc7404 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -101,8 +101,10 @@  DEF_SIMPLE_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", 1)
 /* The cast operator.  */
 DEF_SIMPLE_OPERATOR ("", TYPE_EXPR, "cv", 1)
 DEF_SIMPLE_OPERATOR ("", CAST_EXPR, "cv", 1)
-DEF_SIMPLE_OPERATOR ("", CONST_CAST_EXPR, "cv", 1)
-DEF_SIMPLE_OPERATOR ("", STATIC_CAST_EXPR, "cv", 1)
+DEF_SIMPLE_OPERATOR ("dynamic_cast", DYNAMIC_CAST_EXPR, "dc", 1)
+DEF_SIMPLE_OPERATOR ("reinterpret_cast", REINTERPRET_CAST_EXPR, "rc", 1)
+DEF_SIMPLE_OPERATOR ("const_cast", CONST_CAST_EXPR, "cc", 1)
+DEF_SIMPLE_OPERATOR ("static_cast", STATIC_CAST_EXPR, "sc", 1)
 
 /* Binary operators.  */
 DEF_SIMPLE_OPERATOR ("+", PLUS_EXPR, "pl", 2)
@@ -125,6 +127,7 @@  DEF_SIMPLE_OPERATOR ("&&", TRUTH_ANDIF_EXPR, "aa", 2)
 DEF_SIMPLE_OPERATOR ("||", TRUTH_ORIF_EXPR, "oo", 2)
 DEF_SIMPLE_OPERATOR (",", COMPOUND_EXPR, "cm", 2)
 DEF_SIMPLE_OPERATOR ("->*", MEMBER_REF, "pm", 2)
+DEF_SIMPLE_OPERATOR (".*", DOTSTAR_EXPR, "ds", 2)
 DEF_SIMPLE_OPERATOR ("->", COMPONENT_REF, "pt", 2)
 DEF_SIMPLE_OPERATOR ("[]", ARRAY_REF, "ix", 2)
 DEF_SIMPLE_OPERATOR ("++", POSTINCREMENT_EXPR, "pp", 2)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 77e3388..bc3dd97 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16885,7 +16885,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 
     default:
       /* An unresolved overload is a nondeduced context.  */
-      if (type_unknown_p (parm))
+      if (is_overloaded_fn (parm) || type_unknown_p (parm))
 	return unify_success (explain_p);
       gcc_assert (EXPR_P (parm));
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index dea7632..8ef3e25 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1457,7 +1457,7 @@  is_overloaded_fn (tree x)
    (14.6.2), return the IDENTIFIER_NODE for that name.  Otherwise, return
    NULL_TREE.  */
 
-static tree
+tree
 dependent_name (tree x)
 {
   if (TREE_CODE (x) == IDENTIFIER_NODE)
diff --git a/gcc/testsuite/g++.dg/abi/mangle51.C b/gcc/testsuite/g++.dg/abi/mangle51.C
new file mode 100644
index 0000000..4992f1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle51.C
@@ -0,0 +1,27 @@ 
+// { dg-options "-std=c++0x -fabi-version=0" }
+
+void* operator new (__SIZE_TYPE__, void *p) { return p; }
+int i;
+
+template <unsigned int> struct helper {};
+// { dg-final { scan-assembler "_Z6check1IiEvP6helperIXsznw_T_EEE" } }
+template <class T> void check1( helper<sizeof(new T)> * ) { }
+// { dg-final { scan-assembler "_Z6check2IiEvP6helperIXszgsnw_T_piEEE" } }
+template <class T> void check2( helper<sizeof(::new T())> * ) { }
+// { dg-final { scan-assembler "_Z6check3IiEvP6helperIXsznwadL_Z1iE_T_piLi1EEEE" } }
+template <class T> void check3( helper<sizeof(new (&i) T(1))> * ) { }
+// { dg-final { scan-assembler "_Z7check3aIiEvP6helperIXsznw_T_ilLi1EEEE" } }
+template <class T> void check3a( helper<sizeof(new T{1})> * ) { }
+// { dg-final { scan-assembler "_Z6check4IiEvP6helperIXszna_A1_T_EEE" } }
+template <class T> void check4( helper<sizeof(new T[1])> * ) { }
+// { dg-final { scan-assembler "_Z6check5IiEvP6helperIXszna_A1_T_piEEE" } }
+template <class T> void check5( helper<sizeof(new T[1]())> * ) { }
+int main()
+{
+  check1<int>(0);
+  check2<int>(0);
+  check3<int>(0);
+  check3a<int>(0);
+  check4<int>(0);
+  check5<int>(0);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle52.C b/gcc/testsuite/g++.dg/abi/mangle52.C
new file mode 100644
index 0000000..2c46341
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle52.C
@@ -0,0 +1,21 @@ 
+// { dg-options "-fabi-version=0" }
+
+template <unsigned int> struct helper {};
+// { dg-final { scan-assembler "_Z6check1IiEvP6helperIXszscT_Li1EEE" } }
+template <class T> void check1( helper<sizeof(static_cast<T>(1))> * ) { }
+// { dg-final { scan-assembler "_Z6check2IiXadL_Z1iEEEvP6helperIXszccPT_T0_EE" } }
+template <class T, T* p> void check2( helper<sizeof(const_cast<T*>(p))> * ) { }
+// { dg-final { scan-assembler "_Z6check3IiEvP6helperIXszrcPT_Li0EEE" } }
+template <class T> void check3( helper<sizeof(reinterpret_cast<T*>(0))> * ) { }
+// { dg-final { scan-assembler "_Z6check4I1AXadL_Z1aEEEvP6helperIXszdcPT_T0_EE" } }
+template <class T, T* p> void check4( helper<sizeof(dynamic_cast<T*>(p))> * ) { }
+
+struct A{} a;
+int i;
+int main()
+{
+  check1<int>(0);
+  check2<int,&i>(0);
+  check3<int>(0);
+  check4<A,&a>(0);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle53.C b/gcc/testsuite/g++.dg/abi/mangle53.C
new file mode 100644
index 0000000..b279182
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle53.C
@@ -0,0 +1,13 @@ 
+// { dg-options "-std=c++0x" }
+
+bool b;
+// { dg-final { scan-assembler "_Z1fIiEDTquL_Z1bEfp_twLi42EET_" } }
+template <class T> auto f (T t) -> decltype(b?t:throw 42) { return 0; }
+// { dg-final { scan-assembler "_Z2f2IiEDTquL_Z1bEfp_trET_" } }
+template <class T> auto f2 (T t) -> decltype(b?t:throw) { return 0; }
+
+int main()
+{
+  f(0);
+  f2(0);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle54.C b/gcc/testsuite/g++.dg/abi/mangle54.C
new file mode 100644
index 0000000..ea98df1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle54.C
@@ -0,0 +1,19 @@ 
+// { dg-options "-std=c++0x -fabi-version=0" }
+
+int i;
+// { dg-final { scan-assembler "_Z2f1IiEDTppfp_ET_" } }
+template <class T> auto f1 (T t) -> decltype(t++) { return i; }
+// { dg-final { scan-assembler "_Z2f2IiEDTpp_fp_ET_" } }
+template <class T> auto f2 (T t) -> decltype(++t) { return i; }
+// { dg-final { scan-assembler "_Z2f3IiEDTmmfp_ET_" } }
+template <class T> auto f3 (T t) -> decltype(t--) { return i; }
+// { dg-final { scan-assembler "_Z2f4IiEDTmm_fp_ET_" } }
+template <class T> auto f4 (T t) -> decltype(--t) { return i; }
+
+int main()
+{
+  f1(0);
+  f2(0);
+  f3(0);
+  f4(0);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle55.C b/gcc/testsuite/g++.dg/abi/mangle55.C
new file mode 100644
index 0000000..72caadc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle55.C
@@ -0,0 +1,14 @@ 
+// { dg-options "-std=c++0x" }
+
+struct A { int i; };
+// { dg-final { scan-assembler "_Z2f1Ii1AEDTdsfp_fp0_ET0_MS2_T_" } }
+template <class T, class U> auto f1 (U u, T U::* p) -> decltype(u.*p) { return u.*p; }
+// { dg-final { scan-assembler "_Z2f2Ii1AEDTpmfp_fp0_EPT0_MS2_T_" } }
+template <class T, class U> auto f2 (U* u, T U::* p) -> decltype(u->*p) { return u->*p; }
+
+int main()
+{
+  A a = {};
+  f1(a, &A::i);
+  f2(&a, &A::i);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle56.C b/gcc/testsuite/g++.dg/abi/mangle56.C
new file mode 100644
index 0000000..0fd2701
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle56.C
@@ -0,0 +1,13 @@ 
+// { dg-options "-std=c++0x" }
+
+template <class T> T g(T t1, T t2) { return t2; }
+// { dg-final { scan-assembler "_Z2f1IiEDTcl1gfp_ilEEET_" } }
+template <class T> auto f1 (T t) -> decltype(g(t,{})) { return g(t,{}); }
+// { dg-final { scan-assembler "_Z2f2IiEDTcl1gfp_tlT_EEES0_" } }
+template <class T> auto f2 (T t) -> decltype(g(t,T{})) { return g(t,T{}); }
+
+int main()
+{
+  f1(0);
+  f2(0);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle57.C b/gcc/testsuite/g++.dg/abi/mangle57.C
new file mode 100644
index 0000000..3d9d81e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle57.C
@@ -0,0 +1,16 @@ 
+// { dg-options "-std=c++0x -fabi-version=0" }
+
+template<typename T> int cmp1(T a, T b);
+int cmp2(char a, char b);
+template<typename T, int (*cmp)(T, T)> struct A { };
+// { dg-final { scan-assembler "_Z1fIcEvR1AIT_X4cmp1EE" } }
+template <typename T> void f (A<T,cmp1> &);
+// { dg-final { scan-assembler "_Z1fIcEvR1AIT_L_Z4cmp2ccEE" } }
+template <typename T> void f (A<T,cmp2> &);
+void g()
+{
+  A<char,cmp1> a;
+  f(a);
+  A<char,cmp2> a2;
+  f(a2);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle58.C b/gcc/testsuite/g++.dg/abi/mangle58.C
new file mode 100644
index 0000000..14e5543
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle58.C
@@ -0,0 +1,19 @@ 
+// { dg-options "-std=c++0x -fabi-version=0" }
+
+template<typename T, int (*cmp)(T, T)> struct A { };
+struct B {
+  template<typename T> static int cmp1(T a, T b);
+  static int cmp2(char a, char b);
+  // { dg-final { scan-assembler "_ZN1B1fIcEEvR1AIT_X4cmp1EE" } }
+  template <typename T> static void f (A<T,cmp1> &);
+  // { dg-final { scan-assembler "_ZN1B1fIcEEvR1AIT_L_ZNS_4cmp2EccEE" } }
+  template <typename T> static void f (A<T,cmp2> &);
+};
+
+void g()
+{
+  A<char,B::cmp1> a;
+  B::f(a);
+  A<char,B::cmp2> a2;
+  B::f(a2);
+}
diff --git a/gcc/testsuite/g++.dg/abi/mangle59.C b/gcc/testsuite/g++.dg/abi/mangle59.C
new file mode 100644
index 0000000..3c88ec8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle59.C
@@ -0,0 +1,19 @@ 
+// { dg-options "-std=c++0x -fabi-version=0" }
+
+// { dg-final { scan-assembler "_Z1fIiEDTcmdlfp_psfp_EPT_" } }
+template <class T> auto f (T* p) -> decltype(delete p, +p) { return p; }
+// { dg-final { scan-assembler "_Z1gIiEDTcmgsdlfp_psfp_EPT_" } }
+template <class T> auto g (T* p) -> decltype(::delete p, +p) { return p; }
+// { dg-final { scan-assembler "_Z1hIiEDTcmdafp_psfp_EPT_" } }
+template <class T> auto h (T* p) -> decltype(delete[] p, +p) { return p; }
+// { dg-final { scan-assembler "_Z1iIiEDTcmgsdafp_psfp_EPT_" } }
+template <class T> auto i (T* p) -> decltype(::delete[] p, +p) { return p; }
+
+int main()
+{
+  int x;
+  f(&x);
+  g(&x);
+  h(&x);
+  i(&x);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing3.C b/gcc/testsuite/g++.dg/cpp0x/trailing3.C
index 82d36f0..1c64f45 100644
--- a/gcc/testsuite/g++.dg/cpp0x/trailing3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing3.C
@@ -1,5 +1,5 @@ 
 // More auto/decltype mangling tests.
-// { dg-options "-std=c++0x" }
+// { dg-options "-std=c++0x -fabi-version=0" }
 
 template <class T>
 struct B
@@ -58,6 +58,6 @@  int main()
   A<int>().h(1);
   // { dg-final { scan-assembler  "_ZN1AIiE1jIiEEDTplfp_clL_Z1xvEEET_" } }
   A<int>().j(1);
-  // { dg-final { scan-assembler  "_Z1gIIidEEDTcl1fspplfp_Li1EEEDpT_" } }  
+  // { dg-final { scan-assembler  "_Z1gIJidEEDTcl1fspplfp_Li1EEEDpT_" } }
   g(42, 1.0);
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic111.C b/gcc/testsuite/g++.dg/cpp0x/variadic111.C
index 378162e..cb94ce6 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic111.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic111.C
@@ -1,5 +1,5 @@ 
 // PR c++/48424
-// { dg-options -std=c++0x }
+// { dg-options "-std=c++0x -fabi-version=0" }
 
 template<typename... Args1>
 struct S
@@ -16,4 +16,4 @@  int main()
   s.f(1,2.0,false,'a');
 }
 
-// { dg-final { scan-assembler "_ZN1SIIidEE1fIIbcEEEvidDpOT_" } }
+// { dg-final { scan-assembler "_ZN1SIJidEE1fIJbcEEEvidDpOT_" } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic4.C b/gcc/testsuite/g++.dg/cpp0x/variadic4.C
index 9257a92..1bdad32 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic4.C
@@ -1,4 +1,4 @@ 
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++0x -fabi-version=0" }
 // { dg-do compile }
 template<typename... Args>
 class tuple {};
@@ -9,7 +9,7 @@  void f_two(tuple<int, float>) {}
 void f_nested(tuple<int, tuple<double, char>, float>) { }
 
 
-// { dg-final { scan-assembler "_Z6f_none5tupleIIEE" } }
-// { dg-final { scan-assembler "_Z5f_one5tupleIIiEE" } }
-// { dg-final { scan-assembler "_Z5f_two5tupleIIifEE" } }
-// { dg-final { scan-assembler "_Z8f_nested5tupleIIiS_IIdcEEfEE" } }
+// { dg-final { scan-assembler "_Z6f_none5tupleIJEE" } }
+// { dg-final { scan-assembler "_Z5f_one5tupleIJiEE" } }
+// { dg-final { scan-assembler "_Z5f_two5tupleIJifEE" } }
+// { dg-final { scan-assembler "_Z8f_nested5tupleIJiS_IJdcEEfEE" } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic42.C b/gcc/testsuite/g++.dg/cpp0x/variadic42.C
index 47d9b66..3ec68e8 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic42.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic42.C
@@ -1,4 +1,4 @@ 
-// { dg-options "-std=gnu++0x" }
+// { dg-options "-std=gnu++0x -fabi-version=5" }
 // { dg-do compile }
 template<typename... Args>
 void f(Args...) { }
diff --git a/gcc/testsuite/g++.dg/template/nontype22.C b/gcc/testsuite/g++.dg/template/nontype22.C
index f2c8c46..44d8479 100644
--- a/gcc/testsuite/g++.dg/template/nontype22.C
+++ b/gcc/testsuite/g++.dg/template/nontype22.C
@@ -3,7 +3,7 @@ 
 
 template<typename T> int cmp1(T a, T b);
 template<typename T, int (*cmp)(T, T) = cmp1> struct A { };
-template <typename T> void f (A<T> &); // { dg-bogus "" "" { xfail *-*-* } }
+template <typename T> void f (A<T> &);
 void g()
 {
   A<char> a;
diff --git a/gcc/testsuite/g++.dg/template/pr35240.C b/gcc/testsuite/g++.dg/template/pr35240.C
index 88e2505..5b94551 100644
--- a/gcc/testsuite/g++.dg/template/pr35240.C
+++ b/gcc/testsuite/g++.dg/template/pr35240.C
@@ -1,12 +1,11 @@ 
 // PR c++/35240
 // { dg-do compile }
 
-
 template<int> struct A {};
 
-template<int N> A<sizeof(new int[N][N])> foo(); // { dg-message "unimplemented" }
+template<int N> A<sizeof(new int[N][N])> foo();
 
 void bar()
 {
-  foo<1>(); // { dg-message "required" }
+  foo<1>();
 }
diff --git a/include/demangle.h b/include/demangle.h
index 98b11d7..34b3ed3 100644
--- a/include/demangle.h
+++ b/include/demangle.h
@@ -344,6 +344,9 @@  enum demangle_component_type
      template argument, and the right subtree is either NULL or
      another TEMPLATE_ARGLIST node.  */
   DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+  /* An initializer list.  The left subtree is either an explicit type or
+     NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST.  */
+  DEMANGLE_COMPONENT_INITIALIZER_LIST,
   /* An operator.  This holds information about a standard
      operator.  */
   DEMANGLE_COMPONENT_OPERATOR,
@@ -353,6 +356,8 @@  enum demangle_component_type
   /* A typecast, represented as a unary operator.  The one subtree is
      the type to which the argument should be cast.  */
   DEMANGLE_COMPONENT_CAST,
+  /* A nullary expression.  The left subtree is the operator.  */
+  DEMANGLE_COMPONENT_NULLARY,
   /* A unary expression.  The left subtree is the operator, and the
      right subtree is the single argument.  */
   DEMANGLE_COMPONENT_UNARY,
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 0ed8397..2dfd67c 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -648,9 +648,15 @@  d_dump (struct demangle_component *dc, int indent)
     case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
       printf ("template argument list\n");
       break;
+    case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+      printf ("initializer list\n");
+      break;
     case DEMANGLE_COMPONENT_CAST:
       printf ("cast\n");
       break;
+    case DEMANGLE_COMPONENT_NULLARY:
+      printf ("nullary operator\n");
+      break;
     case DEMANGLE_COMPONENT_UNARY:
       printf ("unary operator\n");
       break;
@@ -806,7 +812,6 @@  d_make_comp (struct d_info *di, enum demangle_component_type type,
     case DEMANGLE_COMPONENT_BINARY_ARGS:
     case DEMANGLE_COMPONENT_TRINARY:
     case DEMANGLE_COMPONENT_TRINARY_ARG1:
-    case DEMANGLE_COMPONENT_TRINARY_ARG2:
     case DEMANGLE_COMPONENT_LITERAL:
     case DEMANGLE_COMPONENT_LITERAL_NEG:
     case DEMANGLE_COMPONENT_COMPOUND_NAME:
@@ -843,6 +848,8 @@  d_make_comp (struct d_info *di, enum demangle_component_type type,
     case DEMANGLE_COMPONENT_PACK_EXPANSION:
     case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
     case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+    case DEMANGLE_COMPONENT_NULLARY:
+    case DEMANGLE_COMPONENT_TRINARY_ARG2:
       if (left == NULL)
 	return NULL;
       break;
@@ -850,6 +857,7 @@  d_make_comp (struct d_info *di, enum demangle_component_type type,
       /* This needs a right parameter, but the left parameter can be
 	 empty.  */
     case DEMANGLE_COMPONENT_ARRAY_TYPE:
+    case DEMANGLE_COMPONENT_INITIALIZER_LIST:
       if (right == NULL)
 	return NULL;
       break;
@@ -1573,15 +1581,17 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "cm", NL (","),         2 },
   { "co", NL ("~"),         1 },
   { "dV", NL ("/="),        2 },
-  { "da", NL ("delete[]"),  1 },
+  { "da", NL ("delete[] "), 1 },
   { "de", NL ("*"),         1 },
-  { "dl", NL ("delete"),    1 },
+  { "dl", NL ("delete "),   1 },
+  { "ds", NL (".*"),        2 },
   { "dt", NL ("."),         2 },
   { "dv", NL ("/"),         2 },
   { "eO", NL ("^="),        2 },
   { "eo", NL ("^"),         2 },
   { "eq", NL ("=="),        2 },
   { "ge", NL (">="),        2 },
+  { "gs", NL ("::"),	    1 },
   { "gt", NL (">"),         2 },
   { "ix", NL ("[]"),        2 },
   { "lS", NL ("<<="),       2 },
@@ -1593,11 +1603,11 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "mi", NL ("-"),         2 },
   { "ml", NL ("*"),         2 },
   { "mm", NL ("--"),        1 },
-  { "na", NL ("new[]"),     1 },
+  { "na", NL ("new[]"),     3 },
   { "ne", NL ("!="),        2 },
   { "ng", NL ("-"),         1 },
   { "nt", NL ("!"),         1 },
-  { "nw", NL ("new"),       1 },
+  { "nw", NL ("new"),       3 },
   { "oR", NL ("|="),        2 },
   { "oo", NL ("||"),        2 },
   { "or", NL ("|"),         2 },
@@ -1614,6 +1624,8 @@  const struct demangle_operator_info cplus_demangle_operators[] =
   { "rs", NL (">>"),        2 },
   { "st", NL ("sizeof "),   1 },
   { "sz", NL ("sizeof "),   1 },
+  { "tr", NL ("throw"),     0 },
+  { "tw", NL ("throw "),    1 },
   { NULL, NULL, 0,          0 }
 };
 
@@ -2679,8 +2691,10 @@  d_template_args (struct d_info *di)
      constructor or destructor.  */
   hold_last_name = di->last_name;
 
-  if (! d_check_char (di, 'I'))
+  if (d_peek_char (di) != 'I'
+      && d_peek_char (di) != 'J')
     return NULL;
+  d_advance (di, 1);
 
   if (d_peek_char (di) == 'E')
     {
@@ -2739,6 +2753,7 @@  d_template_arg (struct d_info *di)
       return d_expr_primary (di);
 
     case 'I':
+    case 'J':
       /* An argument pack.  */
       return d_template_args (di);
 
@@ -2747,15 +2762,16 @@  d_template_arg (struct d_info *di)
     }
 }
 
-/* Subroutine of <expression> ::= cl <expression>+ E */
+/* Parse a sequence of expressions until we hit the terminator
+   character.  */
 
 static struct demangle_component *
-d_exprlist (struct d_info *di)
+d_exprlist (struct d_info *di, char terminator)
 {
   struct demangle_component *list = NULL;
   struct demangle_component **p = &list;
 
-  if (d_peek_char (di) == 'E')
+  if (d_peek_char (di) == terminator)
     {
       d_advance (di, 1);
       return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
@@ -2772,7 +2788,7 @@  d_exprlist (struct d_info *di)
 	return NULL;
       p = &d_right (*p);
 
-      if (d_peek_char (di) == 'E')
+      if (d_peek_char (di) == terminator)
 	{
 	  d_advance (di, 1);
 	  break;
@@ -2863,9 +2879,21 @@  d_expression (struct d_info *di)
       else
 	return name;
     }
+  else if ((peek == 'i' || peek == 't')
+	   && d_peek_next_char (di) == 'l')
+    {
+      /* Brace-enclosed initializer list, untyped or typed.  */
+      struct demangle_component *type = NULL;
+      if (peek == 't')
+	type = cplus_demangle_type (di);
+      d_advance (di, 2);
+      return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
+			  type, d_exprlist (di, 'E'));
+    }
   else
     {
       struct demangle_component *op;
+      const char *code = NULL;
       int args;
 
       op = d_operator_name (di);
@@ -2873,12 +2901,13 @@  d_expression (struct d_info *di)
 	return NULL;
 
       if (op->type == DEMANGLE_COMPONENT_OPERATOR)
-	di->expansion += op->u.s_operator.op->len - 2;
-
-      if (op->type == DEMANGLE_COMPONENT_OPERATOR
-	  && strcmp (op->u.s_operator.op->code, "st") == 0)
-	return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-			    cplus_demangle_type (di));
+	{
+	  code = op->u.s_operator.op->code;
+	  di->expansion += op->u.s_operator.op->len - 2;
+	  if (strcmp (code, "st") == 0)
+	    return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+				cplus_demangle_type (di));
+	}
 
       switch (op->type)
 	{
@@ -2897,26 +2926,43 @@  d_expression (struct d_info *di)
 
       switch (args)
 	{
+	case 0:
+	  return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL);
+
 	case 1:
 	  {
 	    struct demangle_component *operand;
+	    int suffix = 0;
+
+	    if (code && (code[0] == 'p' || code[0] == 'm')
+		&& code[1] == code[0])
+	      /* pp_ and mm_ are the prefix variants.  */
+	      suffix = !d_check_char (di, '_');
+
 	    if (op->type == DEMANGLE_COMPONENT_CAST
 		&& d_check_char (di, '_'))
-	      operand = d_exprlist (di);
+	      operand = d_exprlist (di, 'E');
 	    else
 	      operand = d_expression (di);
-	    return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
-				operand);
+
+	    if (suffix)
+	      /* Indicate the suffix variant for d_print_comp.  */
+	      return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+				  d_make_comp (di,
+					       DEMANGLE_COMPONENT_BINARY_ARGS,
+					       operand, operand));
+	    else
+	      return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+				  operand);
 	  }
 	case 2:
 	  {
 	    struct demangle_component *left;
 	    struct demangle_component *right;
-	    const char *code = op->u.s_operator.op->code;
 
 	    left = d_expression (di);
 	    if (!strcmp (code, "cl"))
-	      right = d_exprlist (di);
+	      right = d_exprlist (di, 'E');
 	    else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
 	      {
 		right = d_unqualified_name (di);
@@ -2936,17 +2982,50 @@  d_expression (struct d_info *di)
 	  {
 	    struct demangle_component *first;
 	    struct demangle_component *second;
+	    struct demangle_component *third;
 
-	    first = d_expression (di);
-	    second = d_expression (di);
+	    if (!strcmp (code, "qu"))
+	      {
+		/* ?: expression.  */
+		first = d_expression (di);
+		second = d_expression (di);
+		third = d_expression (di);
+	      }
+	    else if (code[0] == 'n')
+	      {
+		/* new-expression.  */
+		if (code[1] != 'w' && code[1] != 'a')
+		  return NULL;
+		first = d_exprlist (di, '_');
+		second = cplus_demangle_type (di);
+		if (d_peek_char (di) == 'E')
+		  {
+		    d_advance (di, 1);
+		    third = NULL;
+		  }
+		else if (d_peek_char (di) == 'p'
+			 && d_peek_next_char (di) == 'i')
+		  {
+		    /* Parenthesized initializer.  */
+		    d_advance (di, 2);
+		    third = d_exprlist (di, 'E');
+		  }
+		else if (d_peek_char (di) == 'i'
+			 && d_peek_next_char (di) == 'l')
+		  /* initializer-list.  */
+		  third = d_expression (di);
+		else
+		  return NULL;
+	      }
+	    else
+	      return NULL;
 	    return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
 				d_make_comp (di,
 					     DEMANGLE_COMPONENT_TRINARY_ARG1,
 					     first,
 					     d_make_comp (di,
 							  DEMANGLE_COMPONENT_TRINARY_ARG2,
-							  second,
-							  d_expression (di))));
+							  second, third)));
 	  }
 	default:
 	  return NULL;
@@ -3666,6 +3745,8 @@  d_print_subexpr (struct d_print_info *dpi, int options,
 {
   int simple = 0;
   if (dc->type == DEMANGLE_COMPONENT_NAME
+      || dc->type == DEMANGLE_COMPONENT_QUAL_NAME
+      || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST
       || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
     simple = 1;
   if (!simple)
@@ -4261,6 +4342,19 @@  d_print_comp (struct d_print_info *dpi, int options,
 	}
       return;
 
+    case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+      {
+	struct demangle_component *type = d_left (dc);
+	struct demangle_component *list = d_right (dc);
+
+	if (type)
+	  d_print_comp (dpi, options, type);
+	d_append_char (dpi, '{');
+	d_print_comp (dpi, options, list);
+	d_append_char (dpi, '}');
+      }
+      return;
+
     case DEMANGLE_COMPONENT_OPERATOR:
       {
 	char c;
@@ -4284,55 +4378,59 @@  d_print_comp (struct d_print_info *dpi, int options,
       d_print_cast (dpi, options, dc);
       return;
 
+    case DEMANGLE_COMPONENT_NULLARY:
+      d_print_expr_op (dpi, options, d_left (dc));
+      return;
+
     case DEMANGLE_COMPONENT_UNARY:
-      if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
-	  && d_left (dc)->u.s_operator.op->len == 1
-	  && d_left (dc)->u.s_operator.op->name[0] == '&'
-	  && d_right (dc)->type == DEMANGLE_COMPONENT_TYPED_NAME
-	  && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_QUAL_NAME
-	  && d_right (d_right (dc))->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
-	{
-	  /* Address of a function (therefore in an expression context) must
-	     have its argument list suppressed.
-
-	     unary operator ... dc
-	       operator & ... d_left (dc)
-	       typed name ... d_right (dc)
-		 qualified name ... d_left (d_right (dc))
-		   <names>
-		 function type ... d_right (d_right (dc))
-		   argument list
-		     <arguments>  */
-
-	  d_print_expr_op (dpi, options, d_left (dc));
-	  d_print_comp (dpi, options, d_left (d_right (dc)));
-	  return;
-	}
-      else if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
-	       && d_left (dc)->u.s_operator.op->len == 1
-	       && d_left (dc)->u.s_operator.op->name[0] == '&'
-	       && d_right (dc)->type == DEMANGLE_COMPONENT_QUAL_NAME)
-	{
-	  /* Keep also already processed variant without the argument list.
+      {
+	struct demangle_component *op = d_left (dc);
+	struct demangle_component *operand = d_right (dc);
+	const char *code = NULL;
 
-	     unary operator ... dc
-	       operator & ... d_left (dc)
-	       qualified name ... d_right (dc)
-		 <names>  */
+	if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+	  {
+	    code = op->u.s_operator.op->code;
+	    if (!strcmp (code, "ad"))
+	      {
+		/* Don't print the argument list for the address of a
+		   function.  */
+		if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME
+		    && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME
+		    && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+		  operand = d_left (operand);
+	      }
+	    if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS)
+	      {
+		/* This indicates a suffix operator.  */
+		operand = d_left (operand);
+		d_print_subexpr (dpi, options, operand);
+		d_print_expr_op (dpi, options, op);
+		return;
+	      }
+	  }
 
-	  d_print_expr_op (dpi, options, d_left (dc));
-	  d_print_comp (dpi, options, d_right (dc));
-	  return;
-	}
-      else if (d_left (dc)->type != DEMANGLE_COMPONENT_CAST)
-	d_print_expr_op (dpi, options, d_left (dc));
-      else
-	{
-	  d_append_char (dpi, '(');
-	  d_print_cast (dpi, options, d_left (dc));
-	  d_append_char (dpi, ')');
-	}
-      d_print_subexpr (dpi, options, d_right (dc));
+	if (op->type != DEMANGLE_COMPONENT_CAST)
+	  d_print_expr_op (dpi, options, op);
+	else
+	  {
+	    d_append_char (dpi, '(');
+	    d_print_cast (dpi, options, op);
+	    d_append_char (dpi, ')');
+	  }
+	if (code && !strcmp (code, "gs"))
+	  /* Avoid parens after '::'.  */
+	  d_print_comp (dpi, options, operand);
+	else if (code && !strcmp (code, "st"))
+	  /* Always print parens for sizeof (type).  */
+	  {
+	    d_append_char (dpi, '(');
+	    d_print_comp (dpi, options, operand);
+	    d_append_char (dpi, ')');
+	  }
+	else
+	  d_print_subexpr (dpi, options, operand);
+      }
       return;
 
     case DEMANGLE_COMPONENT_BINARY:
@@ -4397,11 +4495,33 @@  d_print_comp (struct d_print_info *dpi, int options,
 	  d_print_error (dpi);
 	  return;
 	}
-      d_print_subexpr (dpi, options, d_left (d_right (dc)));
-      d_print_expr_op (dpi, options, d_left (dc));
-      d_print_subexpr (dpi, options, d_left (d_right (d_right (dc))));
-      d_append_string (dpi, " : ");
-      d_print_subexpr (dpi, options, d_right (d_right (d_right (dc))));
+      {
+	struct demangle_component *op = d_left (dc);
+	struct demangle_component *first = d_left (d_right (dc));
+	struct demangle_component *second = d_left (d_right (d_right (dc)));
+	struct demangle_component *third = d_right (d_right (d_right (dc)));
+
+	if (!strcmp (op->u.s_operator.op->code, "qu"))
+	  {
+	    d_print_subexpr (dpi, options, first);
+	    d_print_expr_op (dpi, options, op);
+	    d_print_subexpr (dpi, options, second);
+	    d_append_string (dpi, " : ");
+	    d_print_subexpr (dpi, options, third);
+	  }
+	else
+	  {
+	    d_append_string (dpi, "new ");
+	    if (d_left (first) != NULL)
+	      {
+		d_print_subexpr (dpi, options, first);
+		d_append_char (dpi, ' ');
+	      }
+	    d_print_comp (dpi, options, second);
+	    if (third)
+	      d_print_subexpr (dpi, options, third);
+	  }
+      }
       return;
 
     case DEMANGLE_COMPONENT_TRINARY_ARG1:
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 642fe14..3f3960a 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -3935,7 +3935,7 @@  _Z1tIlEDTplcvT_Li5EclL_Z1qsELi6EEEv
 decltype (((long)(5))+(q(6))) t<long>()
 # test for expansion of function parameter pack
 --format=gnu-v3
-_Z1gIIidEEDTclL_Z1fEspplfp_Li1EEEDpT_
+_Z1gIJidEEDTclL_Z1fEspplfp_Li1EEEDpT_
 decltype (f(({parm#1}+(1))...)) g<int, double>(int, double)
 # lambda tests
 --format=gnu-v3
@@ -4030,6 +4030,45 @@  decltype ((int)()) f<int, int>(int, int)
 --format=gnu-v3
 _Z1fDv4_iS_
 f(int __vector(4), int __vector(4))
+--format=gnu-v3
+_Z2f1Ii1AEDTdsfp_fp0_ET0_MS2_T_
+decltype ({parm#1}.*{parm#2}) f1<int, A>(A, int A::*)
+--format=gnu-v3
+_Z2f2IiEDTquL_Z1bEfp_trET_
+decltype (b?{parm#1} : (throw)) f2<int>(int)
+--format=gnu-v3
+_Z6check1IiEvP6helperIXsznw_T_EEE
+void check1<int>(helper<sizeof (new int)>*)
+--format=gnu-v3
+_Z6check2IiEvP6helperIXszgsnw_T_piEEE
+void check2<int>(helper<sizeof (::new int())>*)
+--format=gnu-v3
+_Z6check3IiEvP6helperIXsznwadL_Z1iE_T_piLi1EEEE
+void check3<int>(helper<sizeof (new (&i) int(1))>*)
+--format=gnu-v3
+_Z6check4IiEvP6helperIXszna_A1_T_EEE
+void check4<int>(helper<sizeof (new int [1])>*)
+--format=gnu-v3
+_Z6check5IiEvP6helperIXszna_A1_T_piEEE
+void check5<int>(helper<sizeof (new int [1]())>*)
+--format=gnu-v3
+_Z1fIiEDTcmgsdlfp_psfp_EPT_
+decltype ((::delete {parm#1}),(+{parm#1})) f<int>(int*)
+--format=gnu-v3
+_Z1fIiEDTcmdafp_psfp_EPT_
+decltype ((delete[] {parm#1}),(+{parm#1})) f<int>(int*)
+--format=gnu-v3
+_Z2f1IiEDTppfp_ET_
+decltype ({parm#1}++) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTpp_fp_ET_
+decltype (++{parm#1}) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTcl1gfp_ilEEET_
+decltype (g({parm#1}, {})) f1<int>(int)
+--format=gnu-v3
+_Z2f1IiEDTnw_T_ilEES0_
+decltype (new int{}) f1<int>(int)
 #
 # Ada (GNAT) tests.
 #
diff --git a/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc b/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc
index 49d44bc..12fa6fe 100644
--- a/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc
+++ b/libstdc++-v3/testsuite/abi/demangle/regression/cw-16.cc
@@ -39,7 +39,7 @@  verify_demangle("_Z1fPFYPFiiEiE",
 verify_demangle("_Z1fI1XENT_1tES2_",
                 "X::t f<X>(X::t)");
 verify_demangle("_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE",
-                "void f<5, A>(C<sizeof (T::t), sizeof (T::t)>::q)");
+                "void f<5, A>(C<sizeof (T::t), sizeof T::t>::q)");
 // 2003/12/03, libstdc++/13045
 verify_demangle("_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE",
                 "void f<1, (char)120>(A<(1)+((int)((double)[4028ae147ae147ae]))>)");