diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
index 574f7f6359a8ff95edb131e5353fcb8a2621dc00..82e9186feb0a4120d50a13eb1c83b615ec907a37 100644
--- a/src/libs/cplusplus/LookupContext.cpp
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -1144,9 +1144,29 @@ LookupScope *LookupScopePrivate::lookupType_helper(
     return 0;
 }
 
-static LookupScopePrivate *findSpecializationWithMatchingTemplateArgument(
-        const Name *argumentName, LookupScopePrivate *reference)
+static const NamedType *dereference(const FullySpecifiedType &type)
+{
+    FullySpecifiedType ty = type;
+    forever {
+        if (PointerType *pointer = ty->asPointerType())
+            ty = pointer->elementType();
+        else if (ReferenceType *reference = ty->asReferenceType())
+            ty = reference->elementType();
+        else if (ArrayType *array = ty->asArrayType())
+            ty = array->elementType();
+        else if (const NamedType *namedType = ty->asNamedType())
+            return namedType;
+        else
+            break;
+    }
+    return 0;
+}
+
+static bool findTemplateArgument(const NamedType *namedType, LookupScopePrivate *reference)
 {
+    if (!namedType)
+        return false;
+    const Name *argumentName = namedType->name();
     foreach (Symbol *s, reference->_symbols) {
         if (Class *clazz = s->asClass()) {
             if (Template *templateSpecialization = clazz->enclosingTemplate()) {
@@ -1157,14 +1177,28 @@ static LookupScopePrivate *findSpecializationWithMatchingTemplateArgument(
                             = templateSpecialization->templateParameterAt(i)->asTypenameArgument()) {
                         if (const Name *name = tParam->name()) {
                             if (compareName(name, argumentName))
-                                return reference;
+                                return true;
                         }
                     }
                 }
             }
         }
     }
-    return 0;
+    return false;
+}
+
+static bool matchTypes(const FullySpecifiedType &instantiation,
+                       const FullySpecifiedType &specialization)
+{
+    if (specialization.match(instantiation))
+        return true;
+    if (const NamedType *specName = specialization->asNamedType()) {
+        if (const NamedType *initName = instantiation->asNamedType()) {
+            if (specName->name()->identifier()->match(initName->name()->identifier()))
+                return true;
+        }
+    }
+    return false;
 }
 
 LookupScopePrivate *LookupScopePrivate::findSpecialization(
@@ -1172,7 +1206,6 @@ LookupScopePrivate *LookupScopePrivate::findSpecialization(
         const TemplateNameIdTable &specializations,
         LookupScopePrivate *origin)
 {
-    // we go through all specialization and try to find that one with template argument as pointer
     for (TemplateNameIdTable::const_iterator cit = specializations.begin();
          cit != specializations.end(); ++cit) {
         const TemplateNameId *specializationNameId = cit->first;
@@ -1183,45 +1216,31 @@ LookupScopePrivate *LookupScopePrivate::findSpecialization(
         // and initialization(in future it should be more clever)
         if (specializationTemplateArgumentCount != initializationTemplateArgumentCount)
             continue;
-        for (unsigned i = 0; i < initializationTemplateArgumentCount; ++i) {
+        bool match = true;
+        for (unsigned i = 0; i < initializationTemplateArgumentCount && match; ++i) {
             const FullySpecifiedType &specializationTemplateArgument
                     = specializationNameId->templateArgumentAt(i);
             FullySpecifiedType initializationTemplateArgument = templId->templateArgumentAt(i);
             TypeResolver typeResolver(*_factory);
             Scope *scope = 0;
             typeResolver.resolve(&initializationTemplateArgument, &scope, origin ? origin->q : 0);
-            PointerType *specPointer = specializationTemplateArgument.type()->asPointerType();
             // specialization and initialization argument have to be a pointer
             // additionally type of pointer argument of specialization has to be namedType
-            if (specPointer && initializationTemplateArgument.type()->isPointerType()
-                    && specPointer->elementType().type()->isNamedType()) {
-                return cit->second;
-            }
-
-            ArrayType *specArray = specializationTemplateArgument.type()->asArrayType();
-            if (specArray && initializationTemplateArgument.type()->isArrayType()) {
-                if (const NamedType *argumentNamedType
-                        = specArray->elementType().type()->asNamedType()) {
-                    if (const Name *argumentName = argumentNamedType->name()) {
-                        if (LookupScopePrivate *reference
-                                = findSpecializationWithMatchingTemplateArgument(
-                                    argumentName, cit->second)) {
-                            return reference;
-                        }
-                    }
-                }
-            }
-
-            if (specializationTemplateArgument == initializationTemplateArgument)
-                return cit->second;
-
-            if (const NamedType *specName = specializationTemplateArgument->asNamedType()) {
-                if (const NamedType *initName = initializationTemplateArgument->asNamedType()) {
-                    if (specName->name()->identifier() == initName->name()->identifier())
-                        return cit->second;
-                }
+            if (findTemplateArgument(dereference(specializationTemplateArgument), cit->second)) {
+                if (specializationTemplateArgument->isPointerType())
+                    match = initializationTemplateArgument->isPointerType();
+                else if (specializationTemplateArgument->isReferenceType())
+                    match = initializationTemplateArgument->isReferenceType();
+                else if (specializationTemplateArgument->isArrayType())
+                    match = initializationTemplateArgument->isArrayType();
+                // Do not try exact match (typename T != class T {};)
+            } else {
+                // Real type specialization
+                match = matchTypes(initializationTemplateArgument, specializationTemplateArgument);
             }
         }
+        if (match)
+            return cit->second;
     }
 
     return 0;
diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp
index d8bd4101e23bae6ca250b34ce592c186261555e6..563a6b9a1ce23336417123f84c39aef8a9687706 100644
--- a/src/plugins/cpptools/cppcompletion_test.cpp
+++ b/src/plugins/cpptools/cppcompletion_test.cpp
@@ -1306,22 +1306,29 @@ void CppToolsPlugin::test_completion_data()
             << QLatin1String("Template1"));
 
     QTest::newRow("template_specialization_with_pointer") << _(
-            "template <typename T>\n"
-            "struct Template\n"
-            "{\n"
-            "    T variable;\n"
-            "};\n"
-            "template <typename T>\n"
-            "struct Template<T *>\n"
+            "template <typename T> struct Temp { T variable; };\n"
+            "template <typename T> struct Temp<T *> { T *pointer; };\n"
+            "void func()\n"
             "{\n"
-            "    T *pointer;\n"
-            "};\n"
-            "Template<int*> templ;\n"
-            "@\n"
+            "    Temp<int*> templ;\n"
+            "    @\n"
+            "}"
         ) << _("templ.") << (QStringList()
-            << QLatin1String("Template")
+            << QLatin1String("Temp")
             << QLatin1String("pointer"));
 
+    QTest::newRow("template_specialization_with_reference") << _(
+            "template <typename T> struct Temp { T variable; };\n"
+            "template <typename T> struct Temp<T &> { T reference; };\n"
+            "void func()\n"
+            "{\n"
+            "    Temp<int&> templ;\n"
+            "    @\n"
+            "}"
+        ) << _("templ.") << (QStringList()
+            << QLatin1String("Temp")
+            << QLatin1String("reference"));
+
     QTest::newRow("typedef_using_templates1") << _(
             "namespace NS1\n"
             "{\n"
@@ -2637,6 +2644,22 @@ void CppToolsPlugin::test_completion_data()
         << QLatin1String("i")
         << QLatin1String("s"));
 
+    QTest::newRow("partial_specialization_with_pointer") << _(
+            "struct b {};\n"
+            "struct a : b {};\n"
+            "template<class X, class Y> struct s { float f; };\n"
+            "template<class X> struct s<X, b*> { int i; };\n"
+            "template<class X> struct s<X, a*> { char j; };\n"
+            "\n"
+            "void f()\n"
+            "{\n"
+            "    s<int, a*> var;\n"
+            "    @\n"
+            "}\n"
+    ) << _("var.") << (QStringList()
+        << QLatin1String("j")
+        << QLatin1String("s"));
+
     QTest::newRow("partial_specialization_templated_argument") << _(
             "template<class T> struct t {};\n"
             "\n"
@@ -2652,6 +2675,20 @@ void CppToolsPlugin::test_completion_data()
         << QLatin1String("i")
         << QLatin1String("s"));
 
+    QTest::newRow("specialization_multiple_arguments") << _(
+            "class false_type {};\n"
+            "class true_type {};\n"
+            "template<class T1, class T2> class and_type { false_type f; };\n"
+            "template<> class and_type<true_type, true_type> { true_type t; };\n"
+            "void func()\n"
+            "{\n"
+            "    and_type<true_type, false_type> a;\n"
+            "    @;\n"
+            "}\n"
+     ) << _("a.") << (QStringList()
+        << QLatin1String("f")
+        << QLatin1String("and_type"));
+
     QTest::newRow("auto_declaration_in_if_condition") << _(
             "struct Foo { int bar; };\n"
             "void fun() {\n"