diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 5197284..294ec4c 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -26,6 +26,15 @@ try:
 except ImportError:
     _use_gdb_pp = False
 
+# Try to install type-printers.
+_use_type_printing = False
+try:
+    import gdb.types
+    if hasattr(gdb.types, 'TypePrinter'):
+        _use_type_printing = True
+except ImportError:
+    pass
+
 # Starting with the type ORIG, search for the member type NAME.  This
 # handles searching upward through superclasses.  This is needed to
 # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615.
@@ -801,6 +810,97 @@ class Printer(object):
 
 libstdcxx_printer = None
 
+class FilteringTypePrinter(object):
+    def __init__(self, match, name):
+        self.match = match
+        self.name = name
+        self.enabled = True
+
+    class _recognizer(object):
+        def __init__(self, match, name):
+            self.match = match
+            self.name = name
+            self.type_obj = None
+
+        def recognize(self, type_obj):
+            if type_obj.tag is None:
+                return None
+
+            if self.type_obj is None:
+                if not self.match in type_obj.tag:
+                    # Filter didn't match.
+                    return None
+                try:
+                    self.type_obj = gdb.lookup_type(self.name).strip_typedefs()
+                except:
+                    pass
+            if self.type_obj == type_obj:
+                return self.name
+            return None
+
+    def instantiate(self):
+        return self._recognizer(self.match, self.name)
+
+def add_one_type_printer(obj, match, name):
+    printer = FilteringTypePrinter(match, 'std::' + name)
+    gdb.types.register_type_printer(obj, printer)
+
+def register_type_printers(obj):
+    global _use_type_printing
+
+    if not _use_type_printing:
+        return
+
+    for pfx in ('', 'w'):
+        add_one_type_printer(obj, 'basic_string', pfx + 'string')
+        add_one_type_printer(obj, 'basic_ios', pfx + 'ios')
+        add_one_type_printer(obj, 'basic_streambuf', pfx + 'streambuf')
+        add_one_type_printer(obj, 'basic_istream', pfx + 'istream')
+        add_one_type_printer(obj, 'basic_ostream', pfx + 'ostream')
+        add_one_type_printer(obj, 'basic_iostream', pfx + 'iostream')
+        add_one_type_printer(obj, 'basic_stringbuf', pfx + 'stringbuf')
+        add_one_type_printer(obj, 'basic_istringstream',
+                                 pfx + 'istringstream')
+        add_one_type_printer(obj, 'basic_ostringstream',
+                                 pfx + 'ostringstream')
+        add_one_type_printer(obj, 'basic_stringstream',
+                                 pfx + 'stringstream')
+        add_one_type_printer(obj, 'basic_filebuf', pfx + 'filebuf')
+        add_one_type_printer(obj, 'basic_ifstream', pfx + 'ifstream')
+        add_one_type_printer(obj, 'basic_ofstream', pfx + 'ofstream')
+        add_one_type_printer(obj, 'basic_fstream', pfx + 'fstream')
+        add_one_type_printer(obj, 'basic_regex', pfx + 'regex')
+        add_one_type_printer(obj, 'sub_match', pfx + 'csub_match')
+        add_one_type_printer(obj, 'sub_match', pfx + 'ssub_match')
+        add_one_type_printer(obj, 'match_results', pfx + 'cmatch')
+        add_one_type_printer(obj, 'match_results', pfx + 'smatch')
+        add_one_type_printer(obj, 'regex_iterator', pfx + 'cregex_iterator')
+        add_one_type_printer(obj, 'regex_iterator', pfx + 'sregex_iterator')
+        add_one_type_printer(obj, 'regex_token_iterator',
+                                 pfx + 'cregex_token_iterator')
+        add_one_type_printer(obj, 'regex_token_iterator',
+                                 pfx + 'sregex_token_iterator')
+
+    # Note that we can't have a printer for std::wstreampos, because
+    # it shares the same underlying type as std::streampos.
+    add_one_type_printer(obj, 'fpos', 'streampos')
+    add_one_type_printer(obj, 'basic_string', 'u16string')
+    add_one_type_printer(obj, 'basic_string', 'u32string')
+
+    for dur in ('nanoseconds', 'microseconds', 'milliseconds',
+                'seconds', 'minutes', 'hours'):
+        add_one_type_printer(obj, 'duration', dur)
+
+    add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand0')
+    add_one_type_printer(obj, 'linear_congruential_engine', 'minstd_rand')
+    add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937')
+    add_one_type_printer(obj, 'mersenne_twister_engine', 'mt19937_64')
+    add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux24_base')
+    add_one_type_printer(obj, 'subtract_with_carry_engine', 'ranlux48_base')
+    add_one_type_printer(obj, 'discard_block_engine', 'ranlux24')
+    add_one_type_printer(obj, 'discard_block_engine', 'ranlux48')
+    add_one_type_printer(obj, 'shuffle_order_engine', 'knuth_b')
+
 def register_libstdcxx_printers (obj):
     "Register libstdc++ pretty-printers with objfile Obj."
 
@@ -814,6 +914,8 @@ def register_libstdcxx_printers (obj):
             obj = gdb
         obj.pretty_printers.append(libstdcxx_printer)
 
+    register_type_printers(obj)
+
 def build_libstdcxx_dictionary ():
     global libstdcxx_printer
 
diff --git a/libstdc++-v3/testsuite/lib/gdb-test.exp b/libstdc++-v3/testsuite/lib/gdb-test.exp
index b9d4742..3434ef2 100644
--- a/libstdc++-v3/testsuite/lib/gdb-test.exp
+++ b/libstdc++-v3/testsuite/lib/gdb-test.exp
@@ -67,6 +67,13 @@ proc regexp-test {var result} {
     lappend gdb_tests $var $result 1
 }
 
+# A test of 'whatis'.  This tests a type rather than a variable.
+proc whatis-test {var result} {
+    global gdb_tests
+
+    lappend gdb_tests $var $result whatis
+}
+
 # Utility for testing variable values using gdb, invoked via dg-final.
 # Tests all tests indicated by note-test and regexp-test.
 #
@@ -84,6 +91,12 @@ proc gdb-test { marker {selector {}} } {
 	}
     }
 
+    set do_whatis_tests [gdb_batch_check "python print gdb.type_printers" \
+			   "\\\[\\\]"]
+    if {!$do_whatis_tests} {
+	send_log "skipping 'whatis' tests - gdb too old"
+    }
+
     # This assumes that we are three frames down from dg-test, and that
     # it still stores the filename of the testcase in a local variable "name".
     # A cleaner solution would require a new DejaGnu release.
@@ -109,12 +122,25 @@ proc gdb-test { marker {selector {}} } {
     puts $fd "run"
 
     set count 0
-    foreach {var result is_regexp} $gdb_tests {
-	puts $fd "print $var"
+    foreach {var result kind} $gdb_tests {
 	incr count
 	set gdb_var($count) $var
 	set gdb_expected($count) $result
-	set gdb_is_regexp($count) $is_regexp
+	if {$kind == "whatis"} {
+	    if {$do_whatis_tests} {
+		set gdb_is_type($count) 1
+		set gdb_command($count) "whatis $var"
+	    } else {
+	        unsupported "$testname"
+	        close $fd
+	        return
+	    }
+	} else {
+	    set gdb_is_type($count) 0
+	    set gdb_is_regexp($count) $kind
+	    set gdb_command($count) "print $var"
+	}
+	puts $fd $gdb_command($count)
     }
     set gdb_tests {}
 
@@ -128,28 +154,36 @@ proc gdb-test { marker {selector {}} } {
 	return
     }
 
+    set test_counter 0
     remote_expect target [timeout_value] {
-	-re {^\$([0-9]+) = ([^\n\r]*)[\n\r]+} {
+	-re {^(type|\$([0-9]+)) = ([^\n\r]*)[\n\r]+} {
 	    send_log "got: $expect_out(buffer)"
 
-	    set num $expect_out(1,string)
-	    set first $expect_out(2,string)
-
-	    if {$gdb_is_regexp($num)} {
-		set match [regexp -- $gdb_expected($num) $first]
+	    incr test_counter
+	    set first $expect_out(3,string)
+
+	    if {$gdb_is_type($test_counter)} {
+		if {$expect_out(1,string) != "type"} {
+		    error "gdb failure"
+		}
+		set match [expr {![string compare $first \
+				     $gdb_expected($test_counter)]}]
+	    } elseif {$gdb_is_regexp($test_counter)} {
+		set match [regexp -- $gdb_expected($test_counter) $first]
 	    } else {
-		set match [expr {![string compare $first $gdb_expected($num)]}]
+		set match [expr {![string compare $first \
+				     $gdb_expected($test_counter)]}]
 	    }
 
 	    if {$match} {
-		pass "$testname print $gdb_var($num)"
+		pass "$testname $gdb_command($test_counter)"
 	    } else {
-		fail "$testname print $gdb_var($num)"
+		fail "$testname $gdb_command($test_counter)"
 		verbose "     got =>$first<="
-		verbose "expected =>$gdb_expected($num)<="
+		verbose "expected =>$gdb_expected($test_counter)<="
 	    }
 
-	    if {$num == $count} {
+	    if {$test_counter == $count} {
 		remote_close target
 		return
 	    } else {
@@ -180,16 +214,10 @@ proc gdb-test { marker {selector {}} } {
     return
 }
 
-# Check for a new-enough version of gdb.  The pretty-printer tests
-# require gdb 7.3, but we don't want to test versions, so instead we
-# check for the python "lookup_global_symbol" method, which is in 7.3
-# but not earlier versions.
-# Return 1 if the version is ok, 0 otherwise.
-proc gdb_version_check {} {
-    global gdb_version
-
+# Invoke gdb with a command and pattern-match the output.
+proc gdb_batch_check {command pattern} {
     set gdb_name $::env(GUALITY_GDB_NAME)
-    set cmd "$gdb_name -nw -nx -quiet -batch -ex \"python print gdb.lookup_global_symbol\""
+    set cmd "$gdb_name -nw -nx -quiet -batch -ex \"$command\""
     send_log "Spawning: $cmd\n"
     set res [remote_spawn target "$cmd"]
     if { $res < 0 || $res == "" } {
@@ -197,7 +225,7 @@ proc gdb_version_check {} {
     }
 
     remote_expect target [timeout_value] {
-	-re "<built-in function lookup_global_symbol>" {
+	-re $pattern {
 	    return 1
 	}
 
@@ -215,3 +243,13 @@ proc gdb_version_check {} {
     remote_close target
     return 0
 }
+
+# Check for a new-enough version of gdb.  The pretty-printer tests
+# require gdb 7.3, but we don't want to test versions, so instead we
+# check for the python "lookup_global_symbol" method, which is in 7.3
+# but not earlier versions.
+# Return 1 if the version is ok, 0 otherwise.
+proc gdb_version_check {} {
+    return [gdb_batch_check "python print gdb.lookup_global_symbol" \
+	      "<built-in function lookup_global_symbol>"]
+}
diff --git a/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc
new file mode 100644
index 0000000..c22246c
--- /dev/null
+++ b/libstdc++-v3/testsuite/libstdc++-prettyprinters/whatis.cc
@@ -0,0 +1,243 @@
+// { dg-do run }
+// { dg-options "-g -O0 -std=gnu++11" }
+
+// Copyright (C) 2011, 2012 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <string>
+#include <iostream>
+#include <regex>
+
+template<class T>
+void
+placeholder(const T *s)
+{
+  std::cout << (void *) s;
+}
+
+template<class T>
+struct holder
+{
+  T *f;
+};
+
+typedef std::basic_string<unsigned char> ustring;
+
+// This test is written in a somewhat funny way.
+// Each type under test is used twice: first, to form a pointer type,
+// and second, as a template parameter.  This is done to work around
+// apparent GCC oddities.  The pointer type is needed to ensure that
+// the typedef in question ends up in the debuginfo; while the
+// template type is used to ensure that a typedef-less variant is
+// presented to gdb.
+
+std::string *string_ptr;
+holder<std::string> string_holder;
+// { dg-final { whatis-test string_holder "holder<std::string>" } }
+std::ios *ios_ptr;
+holder<std::ios> ios_holder;
+// { dg-final { whatis-test ios_holder "holder<std::ios>" } }
+std::streambuf *streambuf_ptr;
+holder<std::streambuf> streambuf_holder;
+// { dg-final { whatis-test streambuf_holder "holder<std::streambuf>" } }
+std::istream *istream_ptr;
+holder<std::istream> istream_holder;
+// { dg-final { whatis-test istream_holder "holder<std::istream>" } }
+std::ostream *ostream_ptr;
+holder<std::ostream> ostream_holder;
+// { dg-final { whatis-test ostream_holder "holder<std::ostream>" } }
+std::iostream *iostream_ptr;
+holder<std::iostream> iostream_holder;
+// { dg-final { whatis-test iostream_holder "holder<std::iostream>" } }
+std::stringbuf *stringbuf_ptr;
+holder<std::stringbuf> stringbuf_holder;
+// { dg-final { whatis-test stringbuf_holder "holder<std::stringbuf>" } }
+std::istringstream *istringstream_ptr;
+holder<std::istringstream> istringstream_holder;
+// { dg-final { whatis-test istringstream_holder "holder<std::istringstream>" } }
+std::ostringstream *ostringstream_ptr;
+holder<std::ostringstream> ostringstream_holder;
+// { dg-final { whatis-test ostringstream_holder "holder<std::ostringstream>" } }
+std::stringstream *stringstream_ptr;
+holder<std::stringstream> stringstream_holder;
+// { dg-final { whatis-test stringstream_holder "holder<std::stringstream>" } }
+std::filebuf *filebuf_ptr;
+holder<std::filebuf> filebuf_holder;
+// { dg-final { whatis-test filebuf_holder "holder<std::filebuf>" } }
+std::ifstream *ifstream_ptr;
+holder<std::ifstream> ifstream_holder;
+// { dg-final { whatis-test ifstream_holder "holder<std::ifstream>" } }
+std::ofstream *ofstream_ptr;
+holder<std::ofstream> ofstream_holder;
+// { dg-final { whatis-test ofstream_holder "holder<std::ofstream>" } }
+std::fstream *fstream_ptr;
+holder<std::fstream> fstream_holder;
+// { dg-final { whatis-test fstream_holder "holder<std::fstream>" } }
+std::streampos *streampos_ptr;
+holder<std::streampos> streampos_holder;
+// { dg-final { whatis-test streampos_holder "holder<std::streampos>" } }
+std::regex *regex_ptr;
+holder<std::regex> regex_holder;
+// { dg-final { whatis-test regex_holder "holder<std::regex>" } }
+std::csub_match *csub_match_ptr;
+holder<std::csub_match> csub_match_holder;
+// { dg-final { whatis-test csub_match_holder "holder<std::csub_match>" } }
+std::ssub_match *ssub_match_ptr;
+holder<std::ssub_match> ssub_match_holder;
+// { dg-final { whatis-test ssub_match_holder "holder<std::ssub_match>" } }
+std::cmatch *cmatch_ptr;
+holder<std::cmatch> cmatch_holder;
+// { dg-final { whatis-test cmatch_holder "holder<std::cmatch>" } }
+std::smatch *smatch_ptr;
+holder<std::smatch> smatch_holder;
+// { dg-final { whatis-test smatch_holder "holder<std::smatch>" } }
+std::cregex_iterator *cregex_iterator_ptr;
+holder<std::cregex_iterator> cregex_iterator_holder;
+// { dg-final { whatis-test cregex_iterator_holder "holder<std::cregex_iterator>" } }
+std::sregex_iterator *sregex_iterator_ptr;
+holder<std::sregex_iterator> sregex_iterator_holder;
+// { dg-final { whatis-test sregex_iterator_holder "holder<std::sregex_iterator>" } }
+std::cregex_token_iterator *cregex_token_iterator_ptr;
+holder<std::cregex_token_iterator> cregex_token_iterator_holder;
+// { dg-final { whatis-test cregex_token_iterator_holder "holder<std::cregex_token_iterator>" } }
+std::sregex_token_iterator *sregex_token_iterator_ptr;
+holder<std::sregex_token_iterator> sregex_token_iterator_holder;
+// { dg-final { whatis-test sregex_token_iterator_holder "holder<std::sregex_token_iterator>" } }
+std::u16string *u16string_ptr;
+holder<std::u16string> u16string_holder;
+// { dg-final { whatis-test u16string_holder "holder<std::u16string>" } }
+std::u32string *u32string_ptr;
+holder<std::u32string> u32string_holder;
+// { dg-final { whatis-test u32string_holder "holder<std::u32string>" } }
+std::minstd_rand0 *minstd_rand0_ptr;
+holder<std::minstd_rand0> minstd_rand0_holder;
+// { dg-final { whatis-test minstd_rand0_holder "holder<std::minstd_rand0>" } }
+std::minstd_rand *minstd_rand_ptr;
+holder<std::minstd_rand> minstd_rand_holder;
+// { dg-final { whatis-test minstd_rand_holder "holder<std::minstd_rand>" } }
+std::mt19937 *mt19937_ptr;
+holder<std::mt19937> mt19937_holder;
+// { dg-final { whatis-test mt19937_holder "holder<std::mt19937>" } }
+std::mt19937_64 *mt19937_64_ptr;
+holder<std::mt19937_64> mt19937_64_holder;
+// { dg-final { whatis-test mt19937_64_holder "holder<std::mt19937_64>" } }
+std::ranlux24_base *ranlux24_base_ptr;
+holder<std::ranlux24_base> ranlux24_base_holder;
+// { dg-final { whatis-test ranlux24_base_holder "holder<std::ranlux24_base>" } }
+std::ranlux48_base *ranlux48_base_ptr;
+holder<std::ranlux48_base> ranlux48_base_holder;
+// { dg-final { whatis-test ranlux48_base_holder "holder<std::ranlux48_base>" } }
+std::ranlux24 *ranlux24_ptr;
+holder<std::ranlux24> ranlux24_holder;
+// { dg-final { whatis-test ranlux24_holder "holder<std::ranlux24>" } }
+std::ranlux48 *ranlux48_ptr;
+holder<std::ranlux48> ranlux48_holder;
+// { dg-final { whatis-test ranlux48_holder "holder<std::ranlux48>" } }
+std::knuth_b *knuth_b_ptr;
+holder<std::knuth_b> knuth_b_holder;
+// { dg-final { whatis-test knuth_b_holder "holder<std::knuth_b>" } }
+
+ustring *ustring_ptr;
+holder<ustring> ustring_holder;
+// { dg-final { whatis-test ustring_holder "holder<std::basic_string<unsigned char, std::char_traits<unsigned char>, std::allocator<unsigned char> > >" } }
+
+std::basic_string<signed char> *sstring_ptr;
+holder< std::basic_string<signed char> > sstring_holder;
+// { dg-final { whatis-test sstring_holder "holder<std::basic_string<signed char, std::char_traits<signed char>, std::allocator<signed char> > >" } }
+
+int
+main()
+{
+  placeholder(&ios_ptr);		// Mark SPOT
+  placeholder(&ios_holder);
+  placeholder(&string_ptr);
+  placeholder(&string_holder);
+  placeholder(&streambuf_ptr);
+  placeholder(&streambuf_holder);
+  placeholder(&istream_ptr);
+  placeholder(&istream_holder);
+  placeholder(&ostream_ptr);
+  placeholder(&ostream_holder);
+  placeholder(&iostream_ptr);
+  placeholder(&iostream_holder);
+  placeholder(&stringbuf_ptr);
+  placeholder(&stringbuf_holder);
+  placeholder(&istringstream_ptr);
+  placeholder(&istringstream_holder);
+  placeholder(&ostringstream_ptr);
+  placeholder(&ostringstream_holder);
+  placeholder(&stringstream_ptr);
+  placeholder(&stringstream_holder);
+  placeholder(&filebuf_ptr);
+  placeholder(&filebuf_holder);
+  placeholder(&ifstream_ptr);
+  placeholder(&ifstream_holder);
+  placeholder(&ofstream_ptr);
+  placeholder(&ofstream_holder);
+  placeholder(&fstream_ptr);
+  placeholder(&fstream_holder);
+  placeholder(&streampos_ptr);
+  placeholder(&streampos_holder);
+  placeholder(&regex_ptr);
+  placeholder(&regex_holder);
+  placeholder(&csub_match_ptr);
+  placeholder(&csub_match_holder);
+  placeholder(&ssub_match_ptr);
+  placeholder(&ssub_match_holder);
+  placeholder(&cmatch_ptr);
+  placeholder(&cmatch_holder);
+  placeholder(&smatch_ptr);
+  placeholder(&smatch_holder);
+  placeholder(&cregex_iterator_ptr);
+  placeholder(&cregex_iterator_holder);
+  placeholder(&sregex_iterator_ptr);
+  placeholder(&sregex_iterator_holder);
+  placeholder(&cregex_token_iterator_ptr);
+  placeholder(&cregex_token_iterator_holder);
+  placeholder(&sregex_token_iterator_ptr);
+  placeholder(&sregex_token_iterator_holder);
+  placeholder(&u16string_ptr);
+  placeholder(&u16string_holder);
+  placeholder(&u32string_ptr);
+  placeholder(&u32string_holder);
+  placeholder(&minstd_rand0_ptr);
+  placeholder(&minstd_rand0_holder);
+  placeholder(&minstd_rand_ptr);
+  placeholder(&minstd_rand_holder);
+  placeholder(&mt19937_ptr);
+  placeholder(&mt19937_holder);
+  placeholder(&mt19937_64_ptr);
+  placeholder(&mt19937_64_holder);
+  placeholder(&ranlux24_base_ptr);
+  placeholder(&ranlux24_base_holder);
+  placeholder(&ranlux48_base_ptr);
+  placeholder(&ranlux48_base_holder);
+  placeholder(&ranlux24_ptr);
+  placeholder(&ranlux24_holder);
+  placeholder(&ranlux48_ptr);
+  placeholder(&ranlux48_holder);
+  placeholder(&knuth_b_ptr);
+  placeholder(&knuth_b_holder);
+  placeholder(&ustring_ptr);
+  placeholder(&ustring_holder);
+  placeholder(&sstring_ptr);
+  placeholder(&sstring_holder);
+
+  return 0;
+}
+
+// { dg-final { gdb-test SPOT } }
