diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 042e637f8eac952fb13028dc6bb879ee864f6d19..b5b2b04fe1d810207c735c76bedeaecc4d5c28f5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2009-11-20  Shujing Zhao  <pearly.zhao@oracle.com>
+
+	PR c++/29017
+	* cp-tree.h (composite_pointer_operation): New type.
+	(composite_pointer_type): Adjust prototype with new argument.
+	* typeck.c (composite_pointer_type): Accept
+	composite_pointer_operation as argument and emit diagnostic to be
+	visible to gettext and checked at compile time.
+	(composite_pointer_type_r): Likewise.
+	(common_pointer_type): Update call to composite_pointer_type.
+	(cp_build_binary_op): Likewise.
+	* call.c (build_conditional_expr): Likewise.
+
 2009-11-19  Jason Merrill  <jason@redhat.com>
 
 	PR c++/42115
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3b3ccb66bad2c1d878132fd6ce1641b9cf969ee7..b4c8176c626fa76000993233cc1fdaff7c0682a3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3977,7 +3977,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
 	   || (TYPE_PTRMEMFUNC_P (arg2_type) && TYPE_PTRMEMFUNC_P (arg3_type)))
     {
       result_type = composite_pointer_type (arg2_type, arg3_type, arg2,
-					    arg3, "conditional expression",
+					    arg3, CPO_CONDITIONAL_EXPR,
 					    complain);
       if (result_type == error_mark_node)
 	return error_mark_node;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index cae259b6b36ff3944b4f6431b950448691547dfa..88387705a1b1a7527f4b27bf4df5a59142e39728 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -403,6 +403,17 @@ typedef enum cpp0x_warn_str
   CPP0X_DEFAULTED_DELETED
 } cpp0x_warn_str;
   
+/* The various kinds of operation used by composite_pointer_type. */
+
+typedef enum composite_pointer_operation
+{
+  /* comparison */
+  CPO_COMPARISON,
+  /* conversion */
+  CPO_CONVERSION,
+  /* conditional expression */
+  CPO_CONDITIONAL_EXPR
+} composite_pointer_operation;
 
 /* Macros for access to language-specific slots in an identifier.  */
 
@@ -5281,7 +5292,8 @@ extern void expand_ptrmemfunc_cst		(tree, tree *, tree *);
 extern tree type_after_usual_arithmetic_conversions (tree, tree);
 extern tree common_pointer_type                 (tree, tree);
 extern tree composite_pointer_type		(tree, tree, tree, tree,
-						 const char*, tsubst_flags_t);
+						 composite_pointer_operation, 
+						 tsubst_flags_t);
 extern tree merge_types				(tree, tree);
 extern tree check_return_expr			(tree, bool *);
 extern tree cp_build_binary_op                  (location_t,
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 4c02f78f2b175f12e207b0cd6ced1e270e2583c5..8685530a4ddd31b5ca422705c396305879723f9f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -421,10 +421,11 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
 }
 
 /* Subroutine of composite_pointer_type to implement the recursive
-   case.  See that function for documentation fo the parameters.  */
+   case.  See that function for documentation of the parameters.  */
 
 static tree
-composite_pointer_type_r (tree t1, tree t2, const char* location,
+composite_pointer_type_r (tree t1, tree t2, 
+			  composite_pointer_operation operation,
 			  tsubst_flags_t complain)
 {
   tree pointee1;
@@ -457,14 +458,33 @@ composite_pointer_type_r (tree t1, tree t2, const char* location,
 	    && TREE_CODE (pointee2) == POINTER_TYPE)
 	   || (TYPE_PTR_TO_MEMBER_P (pointee1)
 	       && TYPE_PTR_TO_MEMBER_P (pointee2)))
-    result_type = composite_pointer_type_r (pointee1, pointee2, location,
+    result_type = composite_pointer_type_r (pointee1, pointee2, operation,
 					    complain);
   else
     {
       if (complain & tf_error)
-	permerror (input_location, "%s between distinct pointer types %qT and %qT "
-		   "lacks a cast",
-		   location, t1, t2);
+        {
+          switch (operation)
+            {
+            case CPO_COMPARISON:
+              permerror (input_location, "comparison between "
+                         "distinct pointer types %qT and %qT lacks a cast",
+                         t1, t2);
+              break;
+            case CPO_CONVERSION:
+              permerror (input_location, "conversion between "
+                         "distinct pointer types %qT and %qT lacks a cast",
+                         t1, t2);
+              break;
+            case CPO_CONDITIONAL_EXPR:
+              permerror (input_location, "conditional expression between "
+                         "distinct pointer types %qT and %qT lacks a cast",
+                         t1, t2);
+              break;
+            default:
+              gcc_unreachable ();
+            }
+        }
       result_type = void_type_node;
     }
   result_type = cp_build_qualified_type (result_type,
@@ -477,9 +497,28 @@ composite_pointer_type_r (tree t1, tree t2, const char* location,
       if (!same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
 			TYPE_PTRMEM_CLASS_TYPE (t2))
 	  && (complain & tf_error))
-	permerror (input_location, "%s between distinct pointer types %qT and %qT "
-		   "lacks a cast",
-		   location, t1, t2);
+        {
+          switch (operation)
+            {
+            case CPO_COMPARISON:
+              permerror (input_location, "comparison between "
+                         "distinct pointer types %qT and %qT lacks a cast", 
+                         t1, t2);
+              break;
+            case CPO_CONVERSION:
+              permerror (input_location, "conversion between "
+                         "distinct pointer types %qT and %qT lacks a cast",
+                         t1, t2);
+              break;
+            case CPO_CONDITIONAL_EXPR:
+              permerror (input_location, "conditional expression between "
+                         "distinct pointer types %qT and %qT lacks a cast",
+                         t1, t2);
+              break;
+            default:
+              gcc_unreachable ();
+            }
+        }
       result_type = build_ptrmem_type (TYPE_PTRMEM_CLASS_TYPE (t1),
 				       result_type);
     }
@@ -492,15 +531,17 @@ composite_pointer_type_r (tree t1, tree t2, const char* location,
 }
 
 /* Return the composite pointer type (see [expr.rel]) for T1 and T2.
-   ARG1 and ARG2 are the values with those types.  The LOCATION is a
-   string describing the current location, in case an error occurs.
+   ARG1 and ARG2 are the values with those types.  The OPERATION is to
+   describe the operation between the pointer types,
+   in case an error occurs.
 
    This routine also implements the computation of a common type for
    pointers-to-members as per [expr.eq].  */
 
 tree
 composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
-			const char* location, tsubst_flags_t complain)
+			composite_pointer_operation operation, 
+			tsubst_flags_t complain)
 {
   tree class1;
   tree class2;
@@ -539,9 +580,28 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       tree result_type;
 
       if (TYPE_PTRFN_P (t2) && (complain & tf_error))
-	pedwarn (input_location, OPT_pedantic, "ISO C++ forbids %s "
-		 "between pointer of type %<void *%> and pointer-to-function",
-		 location);
+        {
+          switch (operation)
+              {
+              case CPO_COMPARISON:
+                pedwarn (input_location, OPT_pedantic, 
+                         "ISO C++ forbids comparison between "
+                         "pointer of type %<void *%> and pointer-to-function");
+                break;
+              case CPO_CONVERSION:
+                pedwarn (input_location, OPT_pedantic,
+                         "ISO C++ forbids conversion between "
+                         "pointer of type %<void *%> and pointer-to-function");
+                break;
+              case CPO_CONDITIONAL_EXPR:
+                pedwarn (input_location, OPT_pedantic,
+                         "ISO C++ forbids conditional expression between "
+                         "pointer of type %<void *%> and pointer-to-function");
+                break;
+              default:
+                gcc_unreachable ();
+              }
+        }
       result_type
 	= cp_build_qualified_type (void_type_node,
 				   (cp_type_quals (TREE_TYPE (t1))
@@ -577,17 +637,32 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
 	t1 = (build_pointer_type
 	      (cp_build_qualified_type (class2, TYPE_QUALS (class1))));
       else
-	{
-	  if (complain & tf_error)
-	    error ("%s between distinct pointer types %qT and %qT "
-		   "lacks a cast", location, t1, t2);
-	  return error_mark_node;
-	}
+        {
+          if (complain & tf_error)
+            switch (operation)
+              {
+              case CPO_COMPARISON:
+                error ("comparison between distinct "
+                       "pointer types %qT and %qT lacks a cast", t1, t2);
+                break;
+              case CPO_CONVERSION:
+                error ("conversion between distinct "
+                       "pointer types %qT and %qT lacks a cast", t1, t2);
+                break;
+              case CPO_CONDITIONAL_EXPR:
+                error ("conditional expression between distinct "
+                       "pointer types %qT and %qT lacks a cast", t1, t2);
+                break;
+              default:
+                gcc_unreachable ();
+              }
+          return error_mark_node;
+        }
     }
   /* [expr.eq] permits the application of a pointer-to-member
      conversion to change the class type of one of the types.  */
   else if (TYPE_PTR_TO_MEMBER_P (t1)
-	   && !same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
+           && !same_type_p (TYPE_PTRMEM_CLASS_TYPE (t1),
 			    TYPE_PTRMEM_CLASS_TYPE (t2)))
     {
       class1 = TYPE_PTRMEM_CLASS_TYPE (t1);
@@ -598,15 +673,33 @@ composite_pointer_type (tree t1, tree t2, tree arg1, tree arg2,
       else if (DERIVED_FROM_P (class2, class1))
 	t2 = build_ptrmem_type (class1, TYPE_PTRMEM_POINTED_TO_TYPE (t2));
       else
-	{
-	  if (complain & tf_error)
-	    error ("%s between distinct pointer-to-member types %qT and %qT "
-		   "lacks a cast", location, t1, t2);
-	  return error_mark_node;
-	}
+        {
+          if (complain & tf_error)
+            switch (operation)
+              {
+              case CPO_COMPARISON:
+                error ("comparison between distinct "
+                       "pointer-to-member types %qT and %qT lacks a cast",
+                       t1, t2);
+                break;
+              case CPO_CONVERSION:
+                error ("conversion between distinct "
+                       "pointer-to-member types %qT and %qT lacks a cast",
+                       t1, t2);
+                break;
+              case CPO_CONDITIONAL_EXPR:
+                error ("conditional expression between distinct "
+                       "pointer-to-member types %qT and %qT lacks a cast",
+                       t1, t2);
+                break;
+              default:
+                gcc_unreachable ();
+              }
+          return error_mark_node;
+        }
     }
 
-  return composite_pointer_type_r (t1, t2, location, complain);
+  return composite_pointer_type_r (t1, t2, operation, complain);
 }
 
 /* Return the merged type of two types.
@@ -820,7 +913,7 @@ common_pointer_type (tree t1, tree t2)
               || (TYPE_PTRMEMFUNC_P (t1) && TYPE_PTRMEMFUNC_P (t2)));
 
   return composite_pointer_type (t1, t2, error_mark_node, error_mark_node,
-                                 "conversion", tf_warning_or_error);
+                                 CPO_CONVERSION, tf_warning_or_error);
 }
 
 /* Compare two exception specifier types for exactness or subsetness, if
@@ -3683,7 +3776,7 @@ cp_build_binary_op (location_t location,
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	       || (TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)))
 	result_type = composite_pointer_type (type0, type1, op0, op1,
-					      "comparison", complain);
+					      CPO_COMPARISON, complain);
       else if ((code0 == POINTER_TYPE || TYPE_PTRMEM_P (type0))
 	       && null_ptr_cst_p (op1))
 	{
@@ -3772,8 +3865,8 @@ cp_build_binary_op (location_t location,
 	  tree delta0;
 	  tree delta1;
 
-	  type = composite_pointer_type (type0, type1, op0, op1, "comparison",
-					 complain);
+	  type = composite_pointer_type (type0, type1, op0, op1, 
+					 CPO_COMPARISON, complain);
 
 	  if (!same_type_p (TREE_TYPE (op0), type))
 	    op0 = cp_convert_and_check (type, op0);
@@ -3884,7 +3977,7 @@ cp_build_binary_op (location_t location,
 	shorten = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	result_type = composite_pointer_type (type0, type1, op0, op1,
-					      "comparison", complain);
+					      CPO_COMPARISON, complain);
       break;
 
     case LE_EXPR:
@@ -3904,7 +3997,7 @@ cp_build_binary_op (location_t location,
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	result_type = composite_pointer_type (type0, type1, op0, op1,
-					      "comparison", complain);
+					      CPO_COMPARISON, complain);
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
 	       && integer_zerop (op1))
 	result_type = type0;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fdc14b95b5dfe435a1b0584e34ebf6abac97e8ec..56b217cbe53e7fd3191c355ee5b8fb691ddf6aff 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2009-11-20  Shujing Zhao  <pearly.zhao@oracle.com>
+
+	* g++.old-deja/g++.jason/rfg20.C: Make expected dg-error strings
+	explicit.
+	* g++.old-deja/g++.rfg/00321_01-.C: Likewise.
+	* g++.old-deja/g++.rfg/00324_02-.C: Likewise.
+	* g++.old-deja/g++.law/typeck1.C: Likewise.
+	* g++.old-deja/g++.bugs/900324_02.C: Likewise.
+	* g++.dg/conversion/ptrmem9.C: Likewise.
+	* g++.dg/expr/cond2.C: Likewise.
+
 2009-11-20  Paul Thomas  <pault@gcc.gnu.org>
 	    Janus Weil  <janus@gcc.gnu.org>
 
diff --git a/gcc/testsuite/g++.dg/conversion/ptrmem9.C b/gcc/testsuite/g++.dg/conversion/ptrmem9.C
index 2ccd6837c4719ddd135ab4a93cdffaecc741c917..d4a260f92731ed17a1ccfc6567338a919d215e89 100644
--- a/gcc/testsuite/g++.dg/conversion/ptrmem9.C
+++ b/gcc/testsuite/g++.dg/conversion/ptrmem9.C
@@ -22,5 +22,5 @@ void f ()
 
   pd == pb;
   pd == pbv;  // { dg-error "" }
-  pd == pc;   // { dg-error "" }
+  pd == pc;   // { dg-error "comparison between distinct pointer-to-member types" }
 }
diff --git a/gcc/testsuite/g++.dg/expr/cond2.C b/gcc/testsuite/g++.dg/expr/cond2.C
index d9c2e7031f6a4965fd6cf46793611ee5c7d87964..68a26a22f34ff0e9f1ef9be06f4dbe6d198bced0 100644
--- a/gcc/testsuite/g++.dg/expr/cond2.C
+++ b/gcc/testsuite/g++.dg/expr/cond2.C
@@ -8,5 +8,5 @@ struct IsZero : Term {
 Term*
 IsZero::eval()
 {
-  return true ? new Boolean(false) : this; // { dg-error "" }
+  return true ? new Boolean(false) : this; // { dg-error "conditional expression" }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900324_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900324_02.C
index bb612c66be487b7f0ae8d660487f0d644fbabb1a..b77cc0375a87ab637869033148c43b63c2e8f255 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900324_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900324_02.C
@@ -13,7 +13,7 @@ void (*fp)(void);
 
 void function_1 ()
 {
-  fp = 1 ? function_0 : fp;		// { dg-error "" } 
+  fp = 1 ? function_0 : fp;		// { dg-error "conditional expression|invalid conversion" } 
 }
 
 int main () { return 0; }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/rfg20.C b/gcc/testsuite/g++.old-deja/g++.jason/rfg20.C
index 379629456a388d59cc6ef17cb1286c93a554817f..505f7c94968a27a3d276b9ab954b50114fbb3dff 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/rfg20.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/rfg20.C
@@ -6,5 +6,5 @@ void *vp;
 
 void example ()
 {
-    vp != fp;			// { dg-error "" } no conversion from pfn to void*
+    vp != fp;			// { dg-error "forbids comparison" } no conversion from pfn to void*
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/typeck1.C b/gcc/testsuite/g++.old-deja/g++.law/typeck1.C
index 2b5e230274a7bc7d091e7864923a28f984b2ea83..12a8ff6e8cf4c21646a4ce2378075306a52a8e19 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/typeck1.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/typeck1.C
@@ -13,6 +13,6 @@
 
         int test( const foo* f, const bar* b )
                 {
-                return f == b;// { dg-error "" } 
+                return f == b;// { dg-error "comparison between distinct pointer types" } 
                 }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.rfg/00321_01-.C b/gcc/testsuite/g++.old-deja/g++.rfg/00321_01-.C
index 8d0f35efff67e8a4dd240ee4fb55bbf04fc6e7ea..dcc607e329aec1ac02535f196866fc4255c9e4f0 100644
--- a/gcc/testsuite/g++.old-deja/g++.rfg/00321_01-.C
+++ b/gcc/testsuite/g++.old-deja/g++.rfg/00321_01-.C
@@ -9,6 +9,6 @@ int (*p2)[5];
 void
 test ()
 {
-  p1 == p2;		// { dg-error "" } comparison.*
-  p1 > p2;		// { dg-error "" } comparison.*
+  p1 == p2;		// { dg-error "comparison between distinct pointer types" } comparison.*
+  p1 > p2;		// { dg-error "comparison between distinct pointer types" } comparison.*
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.rfg/00324_02-.C b/gcc/testsuite/g++.old-deja/g++.rfg/00324_02-.C
index 4fc2a50641b8bd2eb8ad82d9bfdf1451d4d57cb9..1e742cb0d04b8f304cc6e74b5fc67e55dc322230 100644
--- a/gcc/testsuite/g++.old-deja/g++.rfg/00324_02-.C
+++ b/gcc/testsuite/g++.old-deja/g++.rfg/00324_02-.C
@@ -12,5 +12,5 @@ int i;
 void
 test ()
 {
-   i ? f : fp; // { dg-error "" } 
+   i ? f : fp; // { dg-error "conditional expression|invalid conversion" } 
 }