diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2f39a9d0e55a6a23a1c6d53d43bb50eac57aa6c0..0a88e629d740669c9d0cc56e2c71655a65a08e93 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2000-11-21  Richard Henderson  <rth@redhat.com>
+
+	* c-common.c (c_unsafe_for_reeval): New function.
+	(add_c_tree_codes): Register it.
+	* c-common.h: Declare it.
+	* tree.c (lang_unsafe_for_reeval): New hook.
+	(unsafe_for_reeval): Call it.
+	* tree.h: Declare it.
+
 2000-11-21  Richard Henderson  <rth@redhat.com>
 
 	* config/i386/i386.c (i386_simplify_dwarf_addr): Simplify @GOT
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 05b7b8a5df0076e2b84a4d6c295ac9c52df8a0c9..59bc43e0f20037e49f1cd8bbc5295f928b3ba333 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -5924,6 +5924,20 @@ c_safe_from_p (target, exp)
   return 1;
 }
 
+/* Hook used by unsafe_for_reeval to handle language-specific tree codes.  */
+
+int
+c_unsafe_for_reeval (exp)
+     tree exp;
+{
+  /* Statement expressions may not be reevaluated.  */
+  if (TREE_CODE (exp) == STMT_EXPR)
+    return 2;
+
+  /* Walk all other expressions.  */
+  return -1;
+}
+
 /* Tree code classes. */
 
 #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
@@ -5971,6 +5985,7 @@ add_c_tree_codes ()
   memcpy (tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
 	  c_tree_code_name,
 	  (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
+  lang_unsafe_for_reeval = c_unsafe_for_reeval;
 }
 
 #define CALLED_AS_BUILT_IN(NODE) \
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 1cce9b55c3df8b2dfa9a866eaf9dfed723b03f1b..5f6e4d2335b3c614387b20285a3d2e223708881d 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -757,9 +757,10 @@ extern struct rtx_def *c_expand_expr            PARAMS ((tree, rtx,
 							 enum expand_modifier));
 
 extern int c_safe_from_p                        PARAMS ((rtx, tree));
-
 #endif
 
+extern int c_unsafe_for_reeval			PARAMS ((tree));
+
 /* In dump.c */
 
 typedef struct dump_info *dump_info_p;
diff --git a/gcc/tree.c b/gcc/tree.c
index 7910449bd34c30ff61678c2a3668ad41626a82ce..dcacdaf1d397943f0100c18ed766a7abe7f9a1b6 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -179,6 +179,9 @@ static void finish_vector_type PARAMS((tree));
 void (*lang_unsave) PARAMS ((tree *));
 void (*lang_unsave_expr_now) PARAMS ((tree));
 
+/* If non-null, these are language-specific helper functions for
+   unsafe_for_reeval.  Return negative to not handle some tree.  */
+int (*lang_unsafe_for_reeval) PARAMS ((tree));
 
 tree global_trees[TI_MAX];
 tree integer_types[itk_none];
@@ -1778,7 +1781,12 @@ unsafe_for_reeval (expr)
       break;
 
     default:
-      /* ??? Add a lang hook if it becomes necessary.  */
+      if (lang_unsafe_for_reeval != 0)
+	{
+	  tmp = (*lang_unsafe_for_reeval) (expr);
+	  if (tmp >= 0)
+	    return tmp;
+	}
       break;
     }
 
diff --git a/gcc/tree.h b/gcc/tree.h
index ac0be894d022b569e3f1477d53cea1bcac0ffb3e..1cf49f1f8729212e137e2048b5eac7284f7fd5cc 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2255,7 +2255,11 @@ extern void (*lang_unsave_expr_now)     PARAMS ((tree));
 /* Return 0 if it is safe to evaluate EXPR multiple times,
    return 1 if it is safe if EXPR is unsaved afterward, or
    return 2 if it is completely unsafe.  */
-extern int unsafe_for_reeval PARAMS ((tree));
+extern int unsafe_for_reeval		PARAMS ((tree));
+
+/* If non-null, these are language-specific helper functions for
+   unsafe_for_reeval.  Return negative to not handle some tree.  */
+extern int (*lang_unsafe_for_reeval)	PARAMS ((tree));
 
 /* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
    or offset that depends on a field within a record.