diff --git a/src/plugins/debugger/namedemangler/globalparsestate.cpp b/src/plugins/debugger/namedemangler/globalparsestate.cpp
index f14cf6aae5b57be053531209f3ad1e47113ce27d..c9841a14719ad9e9425fecfdf07a85b4aaf50b01 100644
--- a/src/plugins/debugger/namedemangler/globalparsestate.cpp
+++ b/src/plugins/debugger/namedemangler/globalparsestate.cpp
@@ -71,7 +71,7 @@ void GlobalParseState::addSubstitution(const ParseTreeNode *node)
 
 void GlobalParseState::addSubstitution(const QByteArray &symbol)
 {
-    if (!symbol.isEmpty() && !m_substitutions.contains(symbol))
+    if (!symbol.isEmpty())
         m_substitutions.append(symbol);
 }
 
diff --git a/src/plugins/debugger/namedemangler/namedemangler.cpp b/src/plugins/debugger/namedemangler/namedemangler.cpp
index 3a4e7cb261f287d3fccdd014ab868d2e347d1086..2414b2f0ba413420c7012e4ce075b37a8410a412 100644
--- a/src/plugins/debugger/namedemangler/namedemangler.cpp
+++ b/src/plugins/debugger/namedemangler/namedemangler.cpp
@@ -73,6 +73,21 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName)
                     "expected one.").arg(m_parseState.m_parseStack.count()));
         }
         m_demangledName = m_parseState.m_parseStack.top()->toByteArray();
+
+        /*
+         * FIXME: This is a hack we do because TypeNode::toByteArray() cannot catch all
+         * all nested reference due to the way substitutions are currently implented.
+         * Note that even with this hack, we do not catch things like
+         * "reference to reference to array", because the operators do not follow each other
+         * in the string.
+         * For a correct solution, we'll probably have to clone substitution nodes instead of
+         * just dumping their strings (which means adding a copy constructor and a clone function
+         * to every node).
+         */
+        m_demangledName.replace("&& &&", "&&");
+        m_demangledName.replace("&& &", "&");
+        m_demangledName.replace(" & &", "&");
+
         success = true;
     } catch (const ParseException &p) {
         m_errorString = QString::fromLocal8Bit("Parse error at index %1 of mangled name '%2': %3.")
diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.cpp b/src/plugins/debugger/namedemangler/parsetreenodes.cpp
index 92f88bfe0b1f364120349cf993a56a753af5cfdb..435c6b564af8980631b41dff108da05d87ba58d1 100644
--- a/src/plugins/debugger/namedemangler/parsetreenodes.cpp
+++ b/src/plugins/debugger/namedemangler/parsetreenodes.cpp
@@ -229,6 +229,7 @@ void BuiltinTypeNode::parse()
     if (next == 'u') {
         m_type = VendorType;
         PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode);
+        parseState()->addSubstitution(this);
         return;
     }
 
@@ -1581,6 +1582,7 @@ bool SubstitutionNode::mangledRepresentationStartsWith(char c)
  *                ::= Si # ::std::basic_istream<char,  std::char_traits<char> >
  *                ::= So # ::std::basic_ostream<char,  std::char_traits<char> >
  *                ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+ *                ::= St <unqualified-name> # ::std::
  */
 void SubstitutionNode::parse()
 {
@@ -1607,7 +1609,13 @@ void SubstitutionNode::parse()
             m_type = ActualSubstitutionType;
             m_substValue = parseState()->substitutionAt(0);
             break;
-        case 't': m_type = StdType; break;
+        case 't':
+            m_type = StdType;
+            if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) {
+                PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedNameNode);
+                parseState()->addSubstitution(this);
+            }
+            break;
         case 'a': m_type = StdAllocType; break;
         case 'b': m_type = StdBasicStringType; break;
         case 's': m_type = FullStdBasicStringType; break;
@@ -1623,7 +1631,12 @@ QByteArray SubstitutionNode::toByteArray() const
 {
     switch (m_type) {
     case ActualSubstitutionType: return m_substValue;
-    case StdType: return "std";
+    case StdType: {
+        QByteArray repr = "std";
+        if (childCount() > 0)
+            repr.append("::").append(CHILD_TO_BYTEARRAY(0));
+        return repr;
+    }
     case StdAllocType: return "std::allocator";
     case StdBasicStringType: return "std::basic_string";
     case FullStdBasicStringType: return "std::basic_string<char, std::char_traits<char>, "
@@ -2194,15 +2207,14 @@ void PrefixNode::parse()
             parseState()->addSubstitution(this);
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode);
         }
-        if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) {
+        if (Prefix2Node::mangledRepresentationStartsWith(PEEK()))
             parseState()->addSubstitution(this);
-            PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node);
-        }
+        PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node);
     } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) {
         PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode);
         if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) {
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode);
-            if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK()))
+            if (Prefix2Node::mangledRepresentationStartsWith(PEEK()))
                 parseState()->addSubstitution(this);
         }
         PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node);
@@ -2210,7 +2222,7 @@ void PrefixNode::parse()
         PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode);
         if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) {
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode);
-            if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK()))
+            if (Prefix2Node::mangledRepresentationStartsWith(PEEK()))
                 parseState()->addSubstitution(this);
         }
         PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix2Node);
@@ -2289,8 +2301,10 @@ void TypeNode::parse()
             parseState()->addSubstitution(this);
         } else if (ArrayTypeNode::mangledRepresentationStartsWith(next)) {
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ArrayTypeNode);
+            parseState()->addSubstitution(this);
         } else if (PointerToMemberTypeNode::mangledRepresentationStartsWith(next)) {
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PointerToMemberTypeNode);
+            parseState()->addSubstitution(this);
         } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) {
             PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode);
             // The type is now a substitution candidate, but the child node may contain a forward
@@ -2378,8 +2392,10 @@ QByteArray TypeNode::toByteArray() const
     QList<const ParseTreeNode *> qualPtrRefList;
     const TypeNode *currentNode = this;
     bool leafType = false;
+    Type lastType = TypeNode::OtherType;
     while (!leafType) {
-        switch (currentNode->m_type) {
+        Type currentType = currentNode->m_type;
+        switch (currentType) {
         case QualifiedType: {
             const CvQualifiersNode * const cvNode
                     = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(currentNode, 0));
@@ -2389,13 +2405,32 @@ QByteArray TypeNode::toByteArray() const
             break;
         }
         case PointerType: case ReferenceType: case RValueType:
-            qualPtrRefList << currentNode;
+            /*
+             * The Standard says (8.3.2/6) that nested references collapse according
+             * to the following rules:
+             *     (1) Reference to reference -> reference
+             *     (2) Reference to rvalue -> reference
+             *     (3) Rvalue to reference -> reference
+             *     (4) Rvalue to Rvalue -> Rvalue
+             */
+            if (currentType == ReferenceType
+                    && (lastType == ReferenceType || lastType == RValueType)) { // (1) and (3)
+                qualPtrRefList.removeLast();
+                qualPtrRefList << currentNode;
+            } else if (currentType == RValueType
+                       && (lastType == ReferenceType || lastType == RValueType)) { // (2) and (4)
+                // Ignore current element.
+                currentType = lastType;
+            } else {
+                qualPtrRefList << currentNode;
+            }
             currentNode = DEMANGLER_CAST(TypeNode, CHILD_AT(currentNode, 0));
             break;
         default:
             leafType = true;
             break;
         }
+        lastType = currentType;
     }
 
     if (qualPtrRefList.isEmpty()) {
@@ -2471,6 +2506,7 @@ QByteArray TypeNode::qualPtrRefListToByteArray(const QList<const ParseTreeNode *
             repr.prepend(n->toByteArray());
         }
     }
+
     return repr;
 }
 
diff --git a/tests/auto/debugger/tst_namedemangler.cpp b/tests/auto/debugger/tst_namedemangler.cpp
index 01578704c791fce22dfb37bfe0934563573c84cf..5567f31c6daf77a0e09d6fb086e3bbc2b6c06033 100644
--- a/tests/auto/debugger/tst_namedemangler.cpp
+++ b/tests/auto/debugger/tst_namedemangler.cpp
@@ -174,6 +174,13 @@ void NameDemanglerAutoTest::testCorrectlyMangledNames()
     TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_DtfL0p_E", "void weirdfunc<int>(int, decltype({param#1}))");
     TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_S0_S0_", "void weirdfunc<int>(int, int, int)");
     TEST_CORRECTLY_MANGLED_NAME("_Z9weirdfuncIiEvT_S0_DtfL0p0_E", "void weirdfunc<int>(int, int, decltype({param#2}))");
+    TEST_CORRECTLY_MANGLED_NAME("_Z8toStringIiESsT_",
+            "std::basic_string<char, std::char_traits<char>, std::allocator<char> > toString<int>(int)");
+
+    // TODO: The rvalue reference at the end has to actually collapse. Remove it once collapsing
+    // is properly implemented.
+    TEST_CORRECTLY_MANGLED_NAME("_ZSt9make_pairIiRA5_KcESt4pairINSt17__decay_and_stripIT_E6__typeENS4_IT0_E6__typeEEOS5_OS8_",
+            "std::pair<std::__decay_and_strip<int>::__type, std::__decay_and_strip<char const (&)[5]>::__type> std::make_pair<int, char const (&)[5]>(int &&, char const (&)[5] &&)");
 
     // All examples from the ABI spec.
     TEST_CORRECTLY_MANGLED_NAME("_ZN1S1xE", "S::x");