diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b1df987227d222fcba5b6b5846e742c7e8814dbf..a4403a38da8bef4b30a7e87a1eabbc24260a2ebd 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2006-10-16  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/28211
+	* parser.c (cp_parser_template_argument): Don't consider "&var" a
+	possible constant-expression.
+	* pt.c (convert_nontype_argument): Refine handling of arguments of
+	pointer type.
+
 2006-10-13  Mark Mitchell  <mark@codesourcery.com>
 
 	PR c++/28506
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index cb357cfd59565dd689ded83d36a9fe2ef7ccc1fb..691b742fd831ae039afe09775f0733173573ae18 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9285,7 +9285,7 @@ cp_parser_template_argument (cp_parser* parser)
 	      /* A variable without external linkage might still be a
 		 valid constant-expression, so no error is issued here
 		 if the external-linkage check fails.  */
-	      if (!DECL_EXTERNAL_LINKAGE_P (argument))
+	      if (!address_p && !DECL_EXTERNAL_LINKAGE_P (argument))
 		cp_parser_simulate_error (parser);
 	    }
 	  else if (is_overloaded_fn (argument))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3106023d89a678c4cf0b5eb81f8e086656e928af..744871f35a1466b7668bc962e8208bedc6628caf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -3655,10 +3655,46 @@ convert_nontype_argument (tree type, tree expr)
 
 	Here, we do not care about functions, as they are invalid anyway
 	for a parameter of type pointer-to-object.  */
-      bool constant_address_p =
-	(TREE_CODE (expr) == ADDR_EXPR
-	 || TREE_CODE (expr_type) == ARRAY_TYPE
-	 || (DECL_P (expr) && DECL_TEMPLATE_PARM_P (expr)));
+
+      if (DECL_P (expr) && DECL_TEMPLATE_PARM_P (expr))
+	/* Non-type template parameters are OK.  */
+	;
+      else if (TREE_CODE (expr) != ADDR_EXPR
+	       && TREE_CODE (expr_type) != ARRAY_TYPE)
+	{
+	  if (TREE_CODE (expr) == VAR_DECL)
+	    {
+	      error ("%qD is not a valid template argument "
+		     "because %qD is a variable, not the address of "
+		     "a variable",
+		     expr, expr);
+	      return NULL_TREE;
+	    }
+	  /* Other values, like integer constants, might be valid
+	     non-type arguments of some other type.  */
+	  return error_mark_node;
+	}
+      else
+	{
+	  tree decl;
+
+	  decl = ((TREE_CODE (expr) == ADDR_EXPR)
+		  ? TREE_OPERAND (expr, 0) : expr);
+	  if (TREE_CODE (decl) != VAR_DECL)
+	    {
+	      error ("%qE is not a valid template argument of type %qT "
+		     "because %qE is not a variable",
+		     expr, type, decl);
+	      return NULL_TREE;
+	    }
+	  else if (!DECL_EXTERNAL_LINKAGE_P (decl))
+	    {
+	      error ("%qE is not a valid template argument of type %qT "
+		     "because %qD does not have external linkage",
+		     expr, type, decl);
+	      return NULL_TREE;
+	    }
+	}
 
       expr = decay_conversion (expr);
       if (expr == error_mark_node)
@@ -3667,13 +3703,6 @@ convert_nontype_argument (tree type, tree expr)
       expr = perform_qualification_conversions (type, expr);
       if (expr == error_mark_node)
 	return error_mark_node;
-
-      if (!constant_address_p)
-	{
-	  error ("%qE is not a valid template argument for type %qT "
-		 "because it is not a constant pointer", expr, type);
-	  return NULL_TREE;
-	}
     }
   /* [temp.arg.nontype]/5, bullet 3
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 519a2c40011ff24a153c49672c81a909a1a90b0e..31144a8ce6e0482472a53bae7815f9c0a56a8b17 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2006-10-16  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c++/28211
+	* g++.dg/tc1/dr49.C: Tweak error messages.
+	* g++.dg/parse/template21.C: New test.
+
 2006-10-15  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
 	PR middle-end/20491
diff --git a/gcc/testsuite/g++.dg/parse/template21.C b/gcc/testsuite/g++.dg/parse/template21.C
new file mode 100644
index 0000000000000000000000000000000000000000..e1ac76916e7bbf013a01efcd65b8dce544d82b4e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/template21.C
@@ -0,0 +1,5 @@
+// PR c++/28211
+
+template <const int*> class Helper { };
+const int foo = 0;
+typedef Helper<&foo> HelperType; // { dg-error "linkage|type" }
diff --git a/gcc/testsuite/g++.dg/tc1/dr49.C b/gcc/testsuite/g++.dg/tc1/dr49.C
index f880e2ac36ac6c164a288e4a449c8d8276ee6662..753d96b6977174804e3f2ea0caa1bf5256cfb23e 100644
--- a/gcc/testsuite/g++.dg/tc1/dr49.C
+++ b/gcc/testsuite/g++.dg/tc1/dr49.C
@@ -10,8 +10,8 @@ template struct R<&p>; // OK
 template struct S<&p>; // OK due to parameter adjustment
 
 int *ptr;
-template struct R<ptr>; // { dg-error "constant" }
-template struct S<ptr>; // { dg-error "constant" }
+template struct R<ptr>; // { dg-error "argument" }
+template struct S<ptr>; // { dg-error "argument" }
 
 int v[5];
 template struct R<v>; // OK due to implicit argument conversion