diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 835aabbdc070325caa0ed05340f2e12c555a91dd..3d7ccc0d82dda175d84d5d4012bdeb5689748148 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,11 @@
 2006-10-03  Mark Mitchell  <mark@codesourcery.com>
 
+	PR c++/29020
+	* friend.c (do_friend): Improve comments; add assertion.
+	* parser.c (cp_parser_nested_name_specifier_opt): Resolve
+	typenames for qualified names used in declarations, even when
+	caching qualified name lookup.
+
 	PR c++/29138
 	* decl2.c (grokfield): Don't handle access declarations here.
 	* parser.c (cp_parser_using_declaration): Handle access
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 0c9712e60ca903ca2cd077dbe83a4ca633acecca..d92df5f6eba3df85ad1519eba905cbcd3a777c61 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -396,21 +396,21 @@ make_friend_class (tree type, tree friend_type, bool complain)
     }
 }
 
-/* Main friend processor.
-
-   CTYPE is the class this friend belongs to.
-
-   DECLARATOR is the name of the friend.
-
-   DECL is the FUNCTION_DECL that the friend is.
-
-   FLAGS is just used for `grokclassfn'.  */
+/* Record DECL (a FUNCTION_DECL) as a friend of the
+   CURRENT_CLASS_TYPE.  If DECL is a member function, CTYPE is the
+   class of which it is a member, as named in the friend declaration.
+   DECLARATOR is the name of the friend.  FUNCDEF_FLAG is true if the
+   friend declaration is a definition of the function.  FLAGS is as
+   for grokclass fn.  */
 
 tree
 do_friend (tree ctype, tree declarator, tree decl,
 	   tree attrlist, enum overload_flags flags,
 	   bool funcdef_flag)
 {
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (!ctype || IS_AGGR_TYPE (ctype));
+
   /* Every decl that gets here is a friend of something.  */
   DECL_FRIEND_P (decl) = 1;
 
@@ -421,8 +421,6 @@ do_friend (tree ctype, tree declarator, tree decl,
 	declarator = DECL_NAME (get_first_fn (declarator));
     }
 
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-
   if (ctype)
     {
       /* CLASS_TEMPLATE_DEPTH counts the number of template headers for
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 05151cd300b763055f26cfa07b7582cd6301889c..2672f15afba7609839506e26d522377de22d7532 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3632,10 +3632,17 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
 	{
 	  /* Grab the nested-name-specifier and continue the loop.  */
 	  cp_parser_pre_parsed_nested_name_specifier (parser);
+	  /* If we originally encountered this nested-name-specifier
+	     with IS_DECLARATION set to false, we will not have
+	     resolved TYPENAME_TYPEs, so we must do so here.  */
 	  if (is_declaration
 	      && TREE_CODE (parser->scope) == TYPENAME_TYPE)
-	    parser->scope = resolve_typename_type (parser->scope,
-						   /*only_current_p=*/false);
+	    {
+	      new_scope = resolve_typename_type (parser->scope,
+						 /*only_current_p=*/false);
+	      if (new_scope != error_mark_node)
+		parser->scope = new_scope;
+	    }
 	  success = true;
 	  continue;
 	}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7cc0dd29aa7cfd3120ca4d1b7da4ecfedd21c0a7..d819ac34178f4f7e5460903838f0a9b60027a7a9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2006-10-03  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/29020
+	* g++.dg/template/friend48.C: New test.
+
 2006-10-04  Paul Thomas  <pault@gcc.gnu.org>
 
 	PR fortran/29098
diff --git a/gcc/testsuite/g++.dg/template/friend48.C b/gcc/testsuite/g++.dg/template/friend48.C
new file mode 100644
index 0000000000000000000000000000000000000000..604697dae7a1fc26e0af1062425d54d8d907322e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/friend48.C
@@ -0,0 +1,12 @@
+// PR c++/29020
+
+template<int> struct A
+{
+  void foo();
+};
+
+struct B
+{
+  template<int N> friend void A<N>::A::foo();
+};
+