diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 703df4babd28efa18c80f90a4d6e663e20af3531..0ae6496ba8a255d7e545f49eaa714833209dfdce 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+2003-07-25  Nathan Sidwell  <nathan@codesourcery.com>
+
+	PR c++/11617
+	* cp-tree.h (qualified_name_lookup_error): Declare.
+	* pt.c (tsubst_qualified_id): Use qualified_name_lookup_error for
+	errors.
+	(tsubst_expr) <DECL_STMT case>: Likewise.
+	(tsubst_copy_and_build) <COMPONENT_REF case>: Likewise.
+	* semantics.c (qualified_name_lookup_error): New, broken out of ...
+	(finish_id_expression): ... here. Use it.
+
 2003-07-25  Falk Hueffner  <falk.hueffner@student.uni-tuebingen.de>
 
 	* cfns.gperf: Add '%%' delimiter to placate gperf 3.0.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8f543b4317e228d12af944989d45383f10d0e5e1..994298a061ceed0bd18ecc5eb4016d996e6327ac 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4159,6 +4159,7 @@ extern tree finish_template_type                (tree, tree, int);
 extern tree finish_base_specifier               (tree, tree, bool);
 extern void finish_member_declaration           (tree);
 extern void check_multiple_declarators          (void);
+extern void qualified_name_lookup_error		(tree, tree);
 extern tree finish_id_expression                (tree, tree, tree,
 						 cp_id_kind *, tree *,
 						 bool, bool, bool *, 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f91dca03c47e665a7bd63d967c5d39b5e1992bdd..24c07bbdb24da71b326d1c39e200a404533bd7dc 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7150,8 +7150,7 @@ tsubst_qualified_id (tree qualified_id, tree args,
     }
 
   if (!BASELINK_P (name) && !DECL_P (expr))
-    expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0,
-				  (complain & tf_error) != 0);
+    expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0, false);
   if (DECL_P (expr))
     check_accessibility_of_qualified_id (expr, 
 					 /*object_type=*/NULL_TREE,
@@ -7168,7 +7167,9 @@ tsubst_qualified_id (tree qualified_id, tree args,
   if (is_template)
     expr = lookup_template_function (expr, template_args);
 
-  if (TYPE_P (scope))
+  if (expr == error_mark_node && complain & tf_error)
+    qualified_name_lookup_error (scope, TREE_OPERAND (qualified_id, 1));
+  else if (TYPE_P (scope))
     {
       expr = (adjust_result_of_qualified_name_lookup 
 	      (expr, scope, current_class_type));
@@ -7589,12 +7590,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	  {
 	    tree scope = DECL_INITIAL (decl);
 	    tree name = DECL_NAME (decl);
+	    tree decl;
 	    
 	    scope = tsubst_expr (scope, args, complain, in_decl);
-	    do_local_using_decl (lookup_qualified_name (scope,
-							name, 
-							/*is_type_p=*/0,
-							/*complain=*/true));
+	    decl = lookup_qualified_name (scope, name,
+					  /*is_type_p=*/0, /*complain=*/false);
+	    if (decl == error_mark_node)
+	      qualified_name_lookup_error (scope, name);
+	    else
+	      do_local_using_decl (decl);
 	  }
 	else
 	  {
@@ -8252,18 +8256,15 @@ tsubst_copy_and_build (tree t,
 	       scope is.  */
 	    tmpl = TREE_OPERAND (TREE_OPERAND (member, 1), 0);
 	    args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
-	    member = lookup_qualified_name (TREE_OPERAND (member, 0),
-					    tmpl, 
-					    /*is_type=*/0,
-					    /*complain=*/true);
+	    member = lookup_qualified_name (TREE_OPERAND (member, 0), tmpl, 
+					    /*is_type=*/0, /*complain=*/false);
 	    if (BASELINK_P (member))
 	      BASELINK_FUNCTIONS (member) 
 		= build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
 			    args);
 	    else
 	      {
-		error ("`%D' is not a member of `%T'",
-		       tmpl, TREE_TYPE (object));
+		qualified_name_lookup_error (TREE_TYPE (object), tmpl);
 		return error_mark_node;
 	      }
 	  }
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 102653a338eb5e0bfbab2118746e7a30f69108be..50c74780daf4be34ad9d63ebc0f2bfb333443a1c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2248,6 +2248,24 @@ check_multiple_declarators (void)
     error ("multiple declarators in template declaration");
 }
 
+/* Issue a diagnostic that NAME cannot be found in SCOPE.  */
+
+void
+qualified_name_lookup_error (tree scope, tree name)
+{
+  if (TYPE_P (scope))
+    {
+      if (!COMPLETE_TYPE_P (scope))
+	error ("incomplete type `%T' used in nested name specifier", scope);
+      else
+	error ("`%D' is not a member of `%T'", name, scope);
+    }
+  else if (scope != global_namespace)
+    error ("`%D' is not a member of `%D'", name, scope);
+  else
+    error ("`::%D' has not been declared", name);
+}
+	      
 /* ID_EXPRESSION is a representation of parsed, but unprocessed,
    id-expression.  (See cp_parser_id_expression for details.)  SCOPE,
    if non-NULL, is the type or namespace used to explicitly qualify
@@ -2307,17 +2325,9 @@ finish_id_expression (tree id_expression,
 	  if (scope && (!TYPE_P (scope) || !dependent_type_p (scope)))
 	    {
 	      /* Qualified name lookup failed, and the qualifying name
-		 was not a dependent type.  That is always an
-		 error.  */
-	      if (TYPE_P (scope) && !COMPLETE_TYPE_P (scope))
-		error ("incomplete type `%T' used in nested name "
-		       "specifier",
-		       scope);
-	      else if (scope != global_namespace)
-		error ("`%D' is not a member of `%D'",
-		       id_expression, scope);
-	      else
-		error ("`::%D' has not been declared", id_expression);
+      		 was not a dependent type.  That is always an
+      		 error.  */
+	      qualified_name_lookup_error (scope, id_expression);
 	      return error_mark_node;
 	    }
 	  else if (!scope)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2e78e1b95bce69931bec0f95a502be18ed2494eb..534bd6be9f242d3d648b58234074bcda66e8e8ec 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,6 +1,10 @@
 2003-07-25  Nathan Sidwell  <nathan@codesourcery.com>
 
-	PR 11596
+	PR c++/11617
+	* g++.dg/template/lookup2.C: New test.
+	* g++.dg/template/memclass1.C: Remove instantiated from error.
+
+	PR c++/11596
 	* g++.dg/template/defarg3.C: New test.
 
 	* g++.dg/ext/packed2.C: Pack member struct too. Explain why.
diff --git a/gcc/testsuite/g++.dg/template/lookup2.C b/gcc/testsuite/g++.dg/template/lookup2.C
new file mode 100644
index 0000000000000000000000000000000000000000..493b807aec98a3b576bdd1065ffbc323395fd370
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/lookup2.C
@@ -0,0 +1,18 @@
+// { dg-do compile }
+
+// Copyright (C) 2003 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 27 Mar 2003 <nathan@codesourcery.com>
+
+// PR 11617: Failed to diagnose missing function.
+
+struct B {};
+
+template <typename T> void Bar ()
+{
+  T::foo (); // { dg-error "is not a member of" "" }
+}
+
+void Foo ()
+{
+  Bar<B> (); // { dg-error "instantiated" "" }
+}
diff --git a/gcc/testsuite/g++.dg/template/memclass1.C b/gcc/testsuite/g++.dg/template/memclass1.C
index d4ce9695d2a5e031e1f8193fd9be22353a751adb..c49ed724d6f7d77a5be6f63a4b4b7ad238e1401b 100644
--- a/gcc/testsuite/g++.dg/template/memclass1.C
+++ b/gcc/testsuite/g++.dg/template/memclass1.C
@@ -15,4 +15,4 @@ template <typename T> struct C
     typedef typename A<T>::template B<U> X; // { dg-error "declared|invalid" }
 };
 
-C<void> c;			// { dg-error "instantiated" }
+C<void> c;