diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 238d0cf..ee72322 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1914,6 +1914,7 @@ struct GTY(()) lang_decl_ns {
 
 struct GTY(()) lang_decl_parm {
   struct lang_decl_base base;
+  int level;
   int index;
 };
 
@@ -2108,6 +2109,13 @@ struct GTY((variable_size)) lang_decl {
 #define DECL_PARM_INDEX(NODE) \
   (LANG_DECL_PARM_CHECK (NODE)->index)
 
+/* The level of a user-declared parameter in its function, starting at 1.
+   A parameter of the function will have level 1; a parameter of the first
+   nested function declarator (i.e. t in void f (void (*p)(T t))) will have
+   level 2.  */
+#define DECL_PARM_LEVEL(NODE) \
+  (LANG_DECL_PARM_CHECK (NODE)->level)
+
 /* Nonzero if the VTT parm has been added to NODE.  */
 #define DECL_HAS_VTT_PARM_P(NODE) \
   (LANG_DECL_FN_CHECK (NODE)->has_vtt_parm_p)
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 4d2ace6..a949681 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -96,6 +96,9 @@ typedef struct GTY(()) globals {
   /* The entity that is being mangled.  */
   tree GTY ((skip)) entity;
 
+  /* How many parameter scopes we are inside.  */
+  int parm_depth;
+
   /* True if the mangling will be different in a future version of the
      ABI.  */
   bool need_abi_warning;
@@ -2270,9 +2273,11 @@ write_bare_function_type (const tree type, const int include_return_type_p,
     write_type (TREE_TYPE (type));
 
   /* Now mangle the types of the arguments.  */
+  ++G.parm_depth;
   write_method_parms (TYPE_ARG_TYPES (type),
 		      TREE_CODE (type) == METHOD_TYPE,
 		      decl);
+  --G.parm_depth;
 }
 
 /* Write the mangled representation of a method parameter list of
@@ -2458,8 +2463,23 @@ write_expression (tree expr)
     {
       /* A function parameter used in a late-specified return type.  */
       int index = DECL_PARM_INDEX (expr);
+      int level = DECL_PARM_LEVEL (expr);
+      int delta = G.parm_depth - level + 1;
       gcc_assert (index >= 1);
-      write_string ("fp");
+      write_char ('f');
+      if (delta != 0)
+	{
+	  /* Let L be the number of function prototype scopes from the
+	     innermost one (in which the parameter reference occurs) up to
+	     (and including) the one containing the declaration of the
+	     referenced parameter.  If the parameter declaration clause of
+	     the innermost function prototype scope has been completely
+	     seen, it is not counted (in that case -- which is perhaps the
+	     most common -- L can be zero).  */
+	  write_char ('L');
+	  write_unsigned_number (delta - 1);
+	}
+      write_char ('p');
       write_compact_number (index - 1);
     }
   else if (DECL_P (expr))
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index e2e5450..4117202 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -1635,6 +1635,22 @@ getdecls (void)
   return current_binding_level->names;
 }
 
+/* Return how many function prototypes we are currently nested inside.  */
+
+int
+function_parm_depth (void)
+{
+  int level = 0;
+  struct cp_binding_level *b;
+
+  for (b = current_binding_level;
+       b->kind == sk_function_parms;
+       b = b->level_chain)
+    ++level;
+
+  return level;
+}
+
 /* For debugging.  */
 static int no_print_functions = 0;
 static int no_print_builtins = 0;
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index f81a565..bfcac69 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -333,6 +333,7 @@ extern bool pushdecl_class_level (tree);
 extern tree pushdecl_namespace_level (tree, bool);
 extern bool push_class_level_binding (tree, tree);
 extern tree getdecls (void);
+extern int function_parm_depth (void);
 extern tree cp_namespace_decls (tree);
 extern void set_decl_namespace (tree, tree, bool);
 extern void push_decl_namespace (tree);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8f4a121..5a2806f 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -15942,6 +15942,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 	{
 	  retrofit_lang_decl (decl);
 	  DECL_PARM_INDEX (decl) = ++index;
+	  DECL_PARM_LEVEL (decl) = function_parm_depth ();
 	}
 
       /* Add the new parameter to the list.  */
diff --git a/gcc/testsuite/g++.dg/abi/mangle39.C b/gcc/testsuite/g++.dg/abi/mangle39.C
index 30a08b0..272385b 100644
--- a/gcc/testsuite/g++.dg/abi/mangle39.C
+++ b/gcc/testsuite/g++.dg/abi/mangle39.C
@@ -1,7 +1,7 @@
 // PR c++/42338
 // { dg-options "-std=c++0x" }
 // { dg-final { scan-assembler "_Z1fIPiEDTcmppfp_Li0EET_" } }
-// { dg-final { scan-assembler "_Z1gIiEvRK1AIT_EDTixfp_Li0EE" } }
+// { dg-final { scan-assembler "_Z1gIiEvRK1AIT_EDTixfL0p_Li0EE" } }
 
 template<typename T>
 auto f(T t) -> decltype(++t, 0)
diff --git a/gcc/testsuite/g++.dg/abi/mangle45.C b/gcc/testsuite/g++.dg/abi/mangle45.C
new file mode 100644
index 0000000..48ae57d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle45.C
@@ -0,0 +1,25 @@
+// Testcase for mangling of parameters used other than in a trailing return type
+// { dg-options -std=c++0x }
+
+template<class T> void f(T p, decltype(p));                // L = 1
+template<class T> void g(T p, decltype(p) (*)());          // L = 1
+// G++ incorrectly rejects these currently.
+// template<class T> void h(T p, auto (*)()->decltype(p));    // L = 1
+// template<class T> void i(T p, auto (*)(T q)->decltype(q)); // L = 0
+// template<class T> void j(T p, auto (*)(decltype(p))->T);   // L = 2
+template<class T> void k(T p, int (*(*)(T* p))[sizeof(p)]); // L = 1
+
+int garg();
+int (*karg (int*))[sizeof(int)];
+int main()
+{
+  // { dg-final { scan-assembler  "_Z1fIiEvT_DtfL0p_E" } }
+  f (1,0);
+  // { dg-final { scan-assembler  "_Z1gIiEvT_PFDtfL0p_EvE" } }
+  g (1,garg);
+  // h (1,0);
+  // i (1,0);
+  // j (1,0);
+  // { dg-final { scan-assembler  "_Z1kIiEvT_PFPAszfL0p__iPS0_E" } }
+  k (1,karg);
+}
