Index: langhooks.h
===================================================================
--- langhooks.h	(revision 169848)
+++ langhooks.h	(working copy)
@@ -299,6 +299,17 @@ struct lang_hooks
 			 location_t loc,
 			 const struct cl_option_handlers *handlers);
 
+  /* Return true if the option COMBINED should affect the option
+     SPECIFIC.  This is used for options like -ffast-math which
+     control several other more specific options like -ferrno-math.
+     If this hook returns false then using the combined option will
+     not affect the specific option.  Note that the specific option
+     may still be changed directly; this only affects the behaviour of
+     the combined option.  This is not used for optimization options
+     (-O1, -Ofast, etc.).  The default version of this hook returns
+     true.  */
+  bool (*apply_combined_option) (size_t combined, size_t specific);
+
   /* Called when all command line options have been parsed to allow
      further processing and initialization
 
Index: langhooks-def.h
===================================================================
--- langhooks-def.h	(revision 169848)
+++ langhooks-def.h	(working copy)
@@ -69,6 +69,7 @@ extern void lhd_init_options (unsigned i
 extern bool lhd_complain_wrong_lang_p (const struct cl_option *);
 extern bool lhd_handle_option (size_t, const char *, int, int, location_t,
 			       const struct cl_option_handlers *);
+extern bool lhd_apply_combined_option (size_t, size_t);
 extern tree lhd_callgraph_analyze_expr (tree *, int *);
 
 
@@ -91,6 +92,7 @@ extern void lhd_omp_firstprivatize_type_
 #define LANG_HOOKS_INITIALIZE_DIAGNOSTICS lhd_initialize_diagnostics
 #define LANG_HOOKS_COMPLAIN_WRONG_LANG_P lhd_complain_wrong_lang_p
 #define LANG_HOOKS_HANDLE_OPTION	lhd_handle_option
+#define LANG_HOOKS_APPLY_COMBINED_OPTION lhd_apply_combined_option
 #define LANG_HOOKS_POST_OPTIONS		lhd_post_options
 #define LANG_HOOKS_MISSING_NORETURN_OK_P hook_bool_tree_true
 #define LANG_HOOKS_GET_ALIAS_SET	lhd_get_alias_set
@@ -267,6 +269,7 @@ extern void lhd_end_section (void);
   LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \
   LANG_HOOKS_COMPLAIN_WRONG_LANG_P, \
   LANG_HOOKS_HANDLE_OPTION, \
+  LANG_HOOKS_APPLY_COMBINED_OPTION, \
   LANG_HOOKS_POST_OPTIONS, \
   LANG_HOOKS_INIT, \
   LANG_HOOKS_FINISH, \
Index: langhooks.c
===================================================================
--- langhooks.c	(revision 169848)
+++ langhooks.c	(working copy)
@@ -355,6 +355,14 @@ lhd_handle_option (size_t code ATTRIBUTE
   return false;
 }
 
+/* By default, combined options always apply.  */
+bool
+lhd_apply_combined_option (size_t combined ATTRIBUTE_UNUSED,
+			   size_t specific ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
 /* The default function to print out name of current function that caused
    an error.  */
 void
Index: opts.c
===================================================================
--- opts.c	(revision 169848)
+++ opts.c	(working copy)
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  
 #include "system.h"
 #include "intl.h"
 #include "coretypes.h"
+#include "tree.h" /* Required by langhooks.h.  */
+#include "langhooks.h"
 #include "tm.h" /* Needed by rtl.h and used for STACK_CHECK_BUILTIN,
 		   STACK_CHECK_STATIC_BUILTIN, DEFAULT_GDB_EXTENSIONS,
 		   DWARF2_DEBUGGING_INFO and DBX_DEBUGGING_INFO.  */
@@ -208,6 +210,7 @@ static void set_fast_math_flags (struct 
 static void decode_d_option (const char *arg, struct gcc_options *opts,
 			     location_t loc, diagnostic_context *dc);
 static void set_unsafe_math_optimizations_flags (struct gcc_options *opts,
+						 size_t code,
 						 int set);
 static void enable_warning_as_error (const char *arg, int value,
 				     unsigned int lang_mask,
@@ -1476,7 +1479,9 @@ common_handle_option (struct gcc_options
       break;
 
     case OPT_funsafe_math_optimizations:
-      set_unsafe_math_optimizations_flags (opts, value);
+      set_unsafe_math_optimizations_flags (opts,
+					   OPT_funsafe_math_optimizations,
+					   value);
       break;
 
     case OPT_ffixed_:
@@ -1757,27 +1762,46 @@ set_Wstrict_aliasing (struct gcc_options
 static void
 set_fast_math_flags (struct gcc_options *opts, int set)
 {
-  opts->x_flag_unsafe_math_optimizations = set;
-  set_unsafe_math_optimizations_flags (opts, set);
-  opts->x_flag_finite_math_only = set;
-  opts->x_flag_errno_math = !set;
+  if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					OPT_funsafe_math_optimizations))
+    {
+      opts->x_flag_unsafe_math_optimizations = set;
+      set_unsafe_math_optimizations_flags (opts, OPT_ffast_math, set);
+    }
+  if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					OPT_ffinite_math_only))
+    opts->x_flag_finite_math_only = set;
+  if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					OPT_fmath_errno))
+    opts->x_flag_errno_math = !set;
   if (set)
     {
-      opts->x_flag_signaling_nans = 0;
-      opts->x_flag_rounding_math = 0;
-      opts->x_flag_cx_limited_range = 1;
+      if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					    OPT_fsignaling_nans))
+	opts->x_flag_signaling_nans = 0;
+      if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					    OPT_frounding_math))
+	opts->x_flag_rounding_math = 0;
+      if (lang_hooks.apply_combined_option (OPT_ffast_math,
+					    OPT_fcx_limited_range))
+	opts->x_flag_cx_limited_range = 1;
     }
 }
 
-/* When -funsafe-math-optimizations is set the following
-   flags are set as well.  */
+/* When -funsafe-math-optimizations is set the following flags are set
+   as well.  CODE is the option code causing this to be called.  */
 static void
-set_unsafe_math_optimizations_flags (struct gcc_options *opts, int set)
+set_unsafe_math_optimizations_flags (struct gcc_options *opts, size_t code,
+				     int set)
 {
-  opts->x_flag_trapping_math = !set;
-  opts->x_flag_signed_zeros = !set;
-  opts->x_flag_associative_math = set;
-  opts->x_flag_reciprocal_math = set;
+  if (lang_hooks.apply_combined_option (code, OPT_ftrapping_math))
+    opts->x_flag_trapping_math = !set;
+  if (lang_hooks.apply_combined_option (code, OPT_fsigned_zeros))
+    opts->x_flag_signed_zeros = !set;
+  if (lang_hooks.apply_combined_option (code, OPT_fassociative_math))
+    opts->x_flag_associative_math = set;
+  if (lang_hooks.apply_combined_option (code, OPT_freciprocal_math))
+    opts->x_flag_reciprocal_math = set;
 }
 
 /* Return true iff flags in OPTS are set as if -ffast-math.  */
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 169848)
+++ Makefile.in	(working copy)
@@ -2780,7 +2780,7 @@ fold-const.o : fold-const.c $(CONFIG_H) 
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    version.h $(INPUT_H) intl.h $(DIAGNOSTIC_H) diagnostic.def
 opts.o : opts.c $(OPTS_H) $(OPTIONS_H) $(DIAGNOSTIC_CORE_H) $(CONFIG_H) $(SYSTEM_H) \
-   coretypes.h $(TM_H) $(RTL_H) \
+   coretypes.h $(TREE_H) langhooks.h $(TM_H) $(RTL_H) \
    $(DIAGNOSTIC_H) $(INSN_ATTR_H) intl.h $(TARGET_H) \
    $(FLAGS_H) $(PARAMS_H) opts-diagnostic.h
 opts-global.o : opts-global.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
