This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GCC RES: Restrictive Exception Specification: 0.1 - Pre-Alpha.


Oops, seems my last email didn't come through anyway.
Anyway, here's the stuff:

RES is my project to test (at compile time) whether C++ code can throw
unhandled exceptions.

I tidied up my source, made a patch, wrote and tested some testcases,
and wrote some documentation.

There should be three attachments here:
- res.diff
- res.txt
- test.tar.gz

I've never made patch files before, but hopefully this one is OK.
I used [diff -Naur original/gcc-3.4.2/gcc res/gcc-3.4.2/gcc > res.diff]
I tested it on a fresh gcc-3.4.2 extract and it worked with [patch -p1
< res.diff]

For a quick test, just call gcc with -Wres (or -Wres-debug to add the
debug info).
I haven't tested on much real-world code, there's a chance it may
still have bugs and segfault or something. It's still pre-alpha
though.

I tried to use GCC coding style but I didn't see an 80 character/line
limit anywhere in the document, so I didn't use any limit.
Perhaps someone will bite me for this or perhaps you'll all celebrate
the beginning of a new era of sensible unlimited lines :) anyway it's
pre-alpha so it hardly matters at present - it's just far easier for
me to read.

Testcases:
Unzip test.tar.gz and read test/tests.txt for instructions.
All the testcases except the last work as they should.
diff -Naur original/gcc-4.3.2/gcc/c-opts.c res/gcc-4.3.2/gcc/c-opts.c
--- original/gcc-4.3.2/gcc/c-opts.c	2008-01-23 03:11:44.000000000 +1300
+++ res/gcc-4.3.2/gcc/c-opts.c	2008-12-16 17:44:42.000000000 +1300
@@ -40,6 +40,8 @@
 #include "mkdeps.h"
 #include "target.h"
 #include "tm_p.h"
+/* <[SPH]> */
+#include "res.h" 
 
 #ifndef DOLLARS_IN_IDENTIFIERS
 # define DOLLARS_IN_IDENTIFIERS true
@@ -510,6 +512,21 @@
 	error ("argument %qs to %<-Wnormalized%> not recognized", arg);
       break;
 
+    /* <[SPH]> */
+    case OPT_Wresl_:
+      res_dwb_add_filelist(arg);
+    case OPT_Wres_cnr:
+    case OPT_Wres_mes:
+    /* Fall through. */
+    case OPT_Wres:
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sWres.", res_intmsg_prefix);
+      res_check_exception_specification = true;
+      warn_restrictive_exception_specification = true;
+      break;
+
+
     case OPT_Wreturn_type:
       warn_return_type = value;
       break;
@@ -530,6 +547,14 @@
       cpp_opts->warn_trigraphs = value;
       break;
 
+    /* <[SPH]> */
+    case OPT_Wtt:
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sWtt.", res_intmsg_prefix);
+      res_check_exception_specification = true;
+      break;
+
     case OPT_Wundef:
       cpp_opts->warn_undef = value;
       break;
@@ -552,6 +577,18 @@
       warn_write_strings = value;
       break;
 
+    /* <[SPH]> */
+    case OPT_Wxesl_:
+      res_dwb_add_filelist(arg);
+    /* Fall through. */
+    case OPT_Wxes:
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sWxes.", res_intmsg_prefix);
+      res_check_exception_specification = true;
+      warn_excessive_exception_specification = true;
+      break;
+
     case OPT_Weffc__:
       warn_ecpp = value;
       if (value)
@@ -1687,3 +1724,247 @@
 	break;
       }
 }
+
+
+
+/* <[SPH]> */
+/* RES: Restrictive Exception Specification. */
+
+bool res_check_exception_specification = FALSE;
+
+/* Internal warning prefix. NULL = no internal warnings. */
+const char* res_intmsg_prefix = RES_INTMSG_PREFIX;
+
+/* RES: Declaration Whitelisting & Blacklisting. */
+
+const char*
+res_system_path = RES_DWB_SYSTEM_DIR;
+
+/* TREE_LISTs of list members. */
+static tree
+res_dwb_filelist = NULL_TREE;
+
+/* Parse the file-list after the command-line option -Wresl=.
+   Save each identified node into res_filelist.
+   Parameters:
+     arg: The null-terminated string argument directly following the command line option. */
+
+void
+res_dwb_add_filelist(const char* arg)
+{
+  tree last_node = NULL_TREE;
+  const char* ch = arg;
+  const char* start = arg;
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%s-Wresl arg = \"%s\".", res_intmsg_prefix, arg);
+
+  /* Parse the file-list.
+     Step through characters one at a time. */
+  while(true)
+    {
+      if(((*ch) == RES_DWB_CHAR_SEPARATOR) || ((*ch) == '\0'))
+        /* New list node. */
+        {
+          bool is_blacklist = false;
+          bool is_system = false;
+          bool is_partial = false;
+          const char* end = ch;
+          int len = end - start;
+
+          /* <TEMP> */
+          /* For disabling verbose debugging output. */
+          if(len > 0)
+            if((*start) == '=')
+              res_intmsg_prefix = NULL;
+
+          if(len > 0)
+            if((*start) == RES_DWB_CHAR_BLACKLIST)
+              /* Blacklist. [-foo.h] makes <foo.h> warnable. */
+              {
+                is_blacklist = true;
+                start++;
+                len--;
+              }
+
+          if(len > 0)
+            if((*start) == RES_DWB_CHAR_SYSTEM)
+              /* System path. [^foo.h] matches <foo.h> not "foo.h". */
+              {
+                is_system = true;
+                start++;
+                len--;
+              }
+
+          if(len > 0)
+            if((*(end - 1)) == RES_DWB_CHAR_PARTIAL)
+              /* Partial match. [foo+] matches any file starting with "foo". */ 
+              {
+                is_partial = true;
+                end--;
+                len--;
+              }
+
+          /* Build and add the new node to the list. */
+          {
+            tree node;
+            size_t flags = 0;
+
+            if(is_blacklist) flags |= RES_DWB_FLAG_BLACKLIST;
+            if(is_system) flags |= RES_DWB_FLAG_SYSTEM;
+            if(is_partial) flags |= RES_DWB_FLAG_PARTIAL;
+
+            /* Build the new node. */
+            node = tree_cons((tree)start, (tree)end, NULL_TREE);
+            TREE_TYPE(node) = (void*)flags;
+
+            /* Attach the new node to the tail of the list. */            
+            if(last_node == NULL_TREE)
+              res_dwb_filelist = node;
+            else
+              TREE_CHAIN(last_node) = node;
+
+            last_node = node;
+          }
+
+          /* <TEMP> */
+          if(res_intmsg_prefix)
+            {
+              char buffer[110];
+              int buffer_len = (len > 100) ? 100 : len;
+              memcpy(buffer, start, buffer_len);
+              buffer[buffer_len] = '\0';
+              /* Eg: [TEST: Added "foo" to blacklist as part user path.] */
+              warning(0l, "%sAdded \"%s\" to %s as %s %s path.", res_intmsg_prefix, buffer, is_blacklist ? "blacklist" : "whitelist", is_partial ? "partial" : "full", is_system ? "system" : "user");
+            }
+          
+          start = ch + 1;
+
+          if((*ch) == '\0')
+            break;
+        }
+     
+      if((*ch) == RES_DWB_CHAR_ESCAPE)
+        /* Escape character. */
+        {
+          ch++;
+          if((*ch) == '\0')
+            /* Escape without following character. */
+            break;
+        }
+
+      ch++;
+    }
+}
+
+/* Check res_whitelist and res_blacklist to see if calls to items declared in the file should generate -Wres warnings.
+   Parameters:
+     name: The filename to be checked.
+   Return:
+     true: Generate -Wres warnings for calls to this file.
+     false: Do not generate -Wres warnings for calls to this file. */
+
+bool
+res_dwb_file_warnable(const char* name_start)
+{
+  bool is_system = false;
+  const char* name_ch = name_start;
+  const char* system_ch = res_system_path;
+  const char* name_end = name_start + strlen(name_start);
+  tree node;
+
+  /* Check whether "name" is inside the system path.
+     Step through characters one at a time. */
+  while(true)
+    {
+      if((*system_ch) == '\0')
+        /* "name" is inside the system path. */
+        {
+          is_system = true;
+          name_start = name_ch;
+          break;
+        }
+
+      /* If (*name_ch) == '\0', will always break here. */
+      if((*name_ch) != (*system_ch))
+        break;
+
+      system_ch++;
+      name_ch++;
+    }
+
+  /* Check every node on the list to see if it matches. */
+  for(node = res_dwb_filelist; node != NULL_TREE; node = TREE_CHAIN(node))
+    {
+      /* Extract flags. */
+      size_t node_flags = (size_t)TREE_TYPE(node);
+      bool node_is_blacklist = (node_flags & RES_DWB_FLAG_BLACKLIST) != 0;
+      bool node_is_system = (node_flags & RES_DWB_FLAG_SYSTEM) != 0;
+      bool node_is_partial = (node_flags & RES_DWB_FLAG_PARTIAL) != 0;
+      const char* node_start;
+      const char* node_end;
+      const char* node_ch;
+      const char* name_ch;
+
+      /* if(node_is_system ^^ is_system) */
+      if((node_is_system && !is_system) || (!node_is_system && is_system))
+        /* Node is a system path but query isn't, or vice-versa. */
+        continue;
+
+      node_start = (const char*)TREE_PURPOSE(node);
+      node_end = (const char*)TREE_VALUE(node);
+
+      /* Step through characters one at a time. */
+      node_ch = node_start;
+      name_ch = name_start;
+      while(true)
+        {
+          if((*node_ch) == RES_DWB_CHAR_ESCAPE)
+            /* Escape character. */
+            {
+              node_ch++;
+              if(node_ch >= node_end)
+                /* Escape without following character. */
+                break;
+            }
+
+          if(node_ch >= node_end)
+            /* Name matched, at least partially. */
+            {
+              if((name_ch == name_end) || node_is_partial)
+                {
+                  /* <TEMP> */
+                  if(res_intmsg_prefix)
+                    {
+                      char buffer[110];
+                      int buffer_len = node_end - node_start;
+                      if(buffer_len > 100)
+                        buffer_len = 100;
+                      memcpy(buffer, node_start, buffer_len);
+                      buffer[buffer_len] = '\0';
+                      /* Eg: [TEST: "foo" matched "f\o". Blacklisted by partial user path.] */
+                      warning(0, "%s\"%s\" matched \"%s\". %s by %s %s path.", res_intmsg_prefix, name_start, buffer, node_is_blacklist ? "Blacklisted" : "Whitelisted", node_is_partial ? "partial" : "full", node_is_system ? "system" : "user");
+                    }
+
+                  return node_is_blacklist;
+                }
+
+              break;
+            }
+
+          if((*node_ch) != (*name_ch))
+            /* Strings don't match. */
+            break;
+
+          node_ch++;
+          name_ch++;
+        }
+    }
+  
+  /* If no list entries match, use the defaults. */
+  if(is_system)
+    return RES_DWB_CHECK_SYSTEM_PATH;
+  else
+    return RES_DWB_CHECK_USER_PATH;
+}
diff -Naur original/gcc-4.3.2/gcc/c.opt res/gcc-4.3.2/gcc/c.opt
--- original/gcc-4.3.2/gcc/c.opt	2008-01-13 13:22:38.000000000 +1300
+++ res/gcc-4.3.2/gcc/c.opt	2008-12-17 01:00:41.000000000 +1300
@@ -393,6 +393,31 @@
 C++ ObjC++ Var(warn_reorder) Warning
 Warn when the compiler reorders code
 
+; <[SPH]>
+Wres
+C++ Var(warn_restrictive_exception_specification) Warning
+Warn when an exception may be thrown that isn't listed in the function's exception specifier
+
+; <[SPH]>
+Wres-bl-unk
+C++ Var(warn_res_blacklist_unknown) Warning
+When using -Wres or -Wxes, this forces checks on declarations not in files, such as builtins. This does not enable -Wres
+
+; <[SPH]>
+Wres-cnr
+C++ Var(warn_res_cnr) Warning
+Additional warning for -Wres that warns when a catch(...) has no rethrow. Using this also enables -Wres
+
+; <[SPH]>
+Wres-mes
+C++ Var(warn_res_mes) Warning
+Additional warning for -Wres that warns when a function lacks an exception specification
+
+; <[SPH]>
+Wresl=
+C++ Warning Joined
+-Wresl=<args> Warn when an exception may be thrown that isn't listed in the function's exception specifier. <args> allows whitelisting calls to functions declared in listed files. See <FIXME> for usage
+
 Wreturn-type
 C ObjC C++ ObjC++ Var(warn_return_type) Warning
 Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++)
@@ -445,6 +470,11 @@
 C ObjC C++ ObjC++ Warning
 Warn if trigraphs are encountered that might affect the meaning of the program
 
+; <[SPH]>
+Wtt
+C++ Var(warn_throw_terminate) Warning
+Warn when an empty throw statement is used outside of a catch block
+
 Wundeclared-selector
 ObjC ObjC++ Var(warn_undeclared_selector) Warning
 Warn about @selector()s without previously declared methods
@@ -473,6 +503,16 @@
 C ObjC C++ ObjC++ Var(warn_write_strings) Warning
 In C++, nonzero means warn about deprecated conversion from string literals to `char *'.  In C, similar warning, except that the conversion is of course not deprecated by the ISO C standard.
 
+; <[SPH]>
+Wxes
+C++ Var(warn_excessive_exception_specification) Warning
+Warn when a catch block or function exception specifier includes a type that will never be thrown past it.
+
+; <[SPH]>
+Wxesl=
+C++ Warning Joined
+-Wxesl=<args> Warn when a catch block or function exception specifier includes a type that will never be thrown past it. <args> allows whitelisting calls to functions declared in listed files. See <FIXME> for usage.
+
 Wpointer-sign
 C ObjC Var(warn_pointer_sign) Init(-1) Warning
 Warn when a pointer differs in signedness in an assignment
diff -Naur original/gcc-4.3.2/gcc/cp/except.c res/gcc-4.3.2/gcc/cp/except.c
--- original/gcc-4.3.2/gcc/cp/except.c	2007-09-06 15:33:46.000000000 +1200
+++ res/gcc-4.3.2/gcc/cp/except.c	2008-12-17 00:59:59.000000000 +1300
@@ -38,6 +38,8 @@
 #include "tree-inline.h"
 #include "tree-iterator.h"
 #include "target.h"
+/* <[SPH]> */
+#include "res.h"
 
 static void push_eh_cleanup (tree);
 static tree prepare_eh_type (tree);
@@ -1015,3 +1017,957 @@
 	  check_handlers_1 (handler, i);
       }
 }
+
+
+
+/* <[SPH]> */
+/* RES: Restrictive Exception Specification.
+   Code for -Wres, -Wres-wl, -Wres-bl, -Wxes, -Wtt
+   These functions are declared in res.h */
+
+static tree
+res_throwable;
+/* This is the TREE_LIST to which thrown types are added.
+   This list is for the innermost try statement-block being parsed, or the function if the parser is not currently inside any try statement-block. */
+
+static tree
+res_catchable;
+/* This is the list of types thrown inside the previous try block that have not yet been matched by a handler. 
+   If the parser is not parsing handlers for a try block this is equal to void_type_node. */
+
+static tree
+res_caught;
+/* Inside catch(type), res_caught = type.
+   Inside catch(...), res_caught = TREE_LIST of remaining throwable types or NULL_TREE if no types.
+   Outside all catch()es, res_caught = void_type_node; */
+
+/* Structure of res_throwable & res_catchable.
+The list nodes have these components:
+- TREE_TYPE(node) = The thrown type.
+- TREE_VALUE(node) = The location where the throw was called.
+    <FIXME>: Currently a size_t typecast to void*.
+- TREE_PURPOSE(node) = The thing throwing the type:
+    If this is a function, this is the function declaration tree.
+    If this is a throw, this is NULL_TREE. <FIXME:Replace with expression?>
+If anything is throwable, there is only one node, whose TREE_TYPE(node) is NULL_TREE.
+If nothing is throwable, the list is empty, equal to NULL_TREE. */
+
+bool
+res_in_function = false;
+/* Indicates whether processing is inside a function. */
+
+
+
+/* Called at the start of a function if res_check_exception_specification is active.
+   Stores the current throwable and catchable lists and catch type, to be recovered when the function ends (useful for function bodies nested inside function bodies).
+   Initialises res_throwable.
+   Parameters:
+     throwable: Pointer to temporary storage for res_throwable.
+     catchable: Pointer to temporary storage for res_catchable.
+     caught: Pointer to temporary storage for res_caught. */
+
+void
+res_on_begin_function(tree* throwable, tree* catchable, tree* caught)
+{
+  /* Temporarily store nested variables. */
+  *throwable = res_throwable;
+  *catchable = res_catchable;
+  *caught = res_caught;
+
+  res_throwable = NULL_TREE;
+  res_catchable = void_type_node;
+  res_caught = void_type_node;
+  res_in_function = true;
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%sfunction begins.", res_intmsg_prefix);
+}
+
+/* Called at the end of a function if res_check_exception_specification is active.
+   Checks the exception specification against types that can be thrown.
+   Outputs warnings if any thrown types aren't in the specification.
+   Parameters:
+     throwable: Pointer to where res_throwable was stored by res_on_begin_function().
+     catchable: Pointer to where res_catchable was stored by res_on_begin_function().
+     caught: Pointer to where res_caught was stored by res_on_begin_function().
+     function: The FUNCTION_DECL for the ending function. */
+
+void
+res_on_end_function(tree* throwable, tree* catchable, tree* caught, tree function)
+{
+  tree functype = TREE_TYPE(function);
+  tree exceptions = TYPE_RAISES_EXCEPTIONS(functype);
+
+  /* <FIXME> Unnecessary? */
+  /* Check whether res_on_begin_function() was called for this function.
+     Protects against checking clones. */
+  /*if(!res_in_function)
+    return;
+  else
+    res_in_function = false;*/
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    {
+      warning(0, "%sfunction %q+F ends.", res_intmsg_prefix, function);
+      res_warnlist(res_throwable);
+    }
+
+  /* -Wres, -Wresl= */
+  if(warn_restrictive_exception_specification)
+    res_check_res(function, exceptions);
+
+  /* -Wxes, -Wxesl= */
+  if(warn_excessive_exception_specification)
+    res_check_xes(function, exceptions);
+
+  res_empty(&res_throwable);
+
+  /* Recover previous values. */
+  res_throwable = *throwable;
+  res_catchable = *catchable;
+  res_caught = *caught;
+}
+
+/* Checks the exception specification against types that can be thrown.
+   Warns when thrown types aren't matched by a specification entry.
+   Parameters:
+     function: The FUNCTION_DECL for the ending function.
+     exceptions: The exception specifier for function. */
+
+void
+res_check_res(tree function, tree exceptions)
+{
+  tree list_node;
+  int unmatched = 0;
+
+  /* If the function does not have an exception specification, it may throw any exception. */
+  if(exceptions == NULL_TREE)
+    {
+      /* -Wres-mes */
+      if(warn_res_mes)
+        warning(0, "RES: %q+F has no exception specification.", function);
+
+      return;
+    }
+
+  /* No exceptions can propogate to outside the function. */
+  if(res_throwable == NULL_TREE)
+    return;
+
+  if(TREE_TYPE(res_throwable) == NULL_TREE)
+    /* The function calls another function without an exception specification, and does not catch this. */
+    {
+      tree thrower = TREE_PURPOSE(res_throwable);
+      location_t loc = (size_t)TREE_VALUE(res_throwable);
+
+      if(thrower != NULL_TREE)
+        if(TREE_CODE(thrower) == FUNCTION_DECL)
+          {
+            warning(0, "RES: %q+F may terminate due to the uncaught and unspecified exceptions from calls to %qF, which may throw anything.", function, thrower);
+            inform("RES: %qF called here.%H", thrower, &loc);
+            inform("RES: %q+F declared here.", thrower);
+            return;
+          }
+
+      /* This is unlikely to be called unless RES_CALCULATE_CATCH_ANY_RETHROW is false. */
+      warning(0, "RES: %q+F may terminate due to uncaught and unspecified exceptions, which may be of any type.", function);
+      return;
+    }
+
+  if(TREE_VALUE(exceptions) == NULL_TREE)
+    /* The function is defined as throw(). */
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sCan't throw anything.", res_intmsg_prefix);
+
+      exceptions = NULL_TREE;
+    }
+
+  /* Check all possibly thrown types vs the function's exception specification. */
+  for(list_node = res_throwable; list_node != NULL_TREE; list_node = TREE_CHAIN(list_node))
+    {
+      tree type;
+      tree thrower;
+      location_t loc;
+      tree spec_node;
+
+      type = TREE_TYPE(list_node);
+      thrower = TREE_PURPOSE(list_node);
+      loc = (location_t)(size_t)TREE_VALUE(list_node);
+
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%s%qT.%H", res_intmsg_prefix, type, &loc);
+
+      /* Step through all types in the exception specification, exiting if a match is found */
+      for(spec_node = exceptions; spec_node != NULL_TREE; spec_node = TREE_CHAIN(spec_node))
+        {
+          tree spec_type = TREE_VALUE(spec_node);
+          if(same_or_base_type_p(spec_type, type))
+            {
+              /* <TEMP> */
+              if(res_intmsg_prefix)
+                warning(0, "%smatched by %qT.", res_intmsg_prefix, spec_type);
+              break;
+            }
+        }
+
+      if(spec_node == NULL_TREE)
+        /* Thrown type isn't part of the exception specification. */
+        {
+          unmatched++;
+
+          if(unmatched == 1)
+            warning(0, "RES: %q+F may terminate due to the following uncaught and unspecified exceptions:", function);
+
+          if(unmatched <= RES_MAX_RES_EXCEPTIONS_LISTED)
+            {
+              if(thrower != NULL_TREE)
+                switch(TREE_CODE(thrower))
+                  {
+                    case FUNCTION_DECL:
+                      {
+                        const char* filename = DECL_SOURCE_FILE(thrower);
+                        int line = DECL_SOURCE_LINE(thrower);
+                        inform("RES: %qT from %qF (declaration at %s:%d).%H", type, thrower, filename, line, &loc);
+                      }
+                    break;
+                    default:
+                      inform("RES: %qT from here.%H", type, &loc);
+                  }
+              else
+                inform("RES: %qT from here.%H", type, &loc);
+            }
+        }
+    }
+
+  if(unmatched > RES_MAX_RES_EXCEPTIONS_LISTED)
+    {
+      int unlisted;
+      unlisted = unmatched - RES_MAX_RES_EXCEPTIONS_LISTED;
+      inform("RES: %d further unlisted type%s may be thrown.", unlisted, (unlisted == 1) ? "" : "s");
+    }
+}
+
+/* Checks the exception specification against types that can be thrown.
+   Warns when specification entries aren't matched by a thrown type.
+   Parameters:
+     function: The FUNCTION_DECL for the ending function.
+     exceptions: The exception specifier for function. */
+
+void
+res_check_xes(tree function, tree exceptions)
+{
+  int unmatched = 0;
+  tree spec_node;
+
+  if(exceptions == NULL_TREE)
+    /* If the function does not have an exception specifier, it may throw any exception. */
+    {
+      if(res_throwable == NULL_TREE)
+        warning(0, "XES: %q+F has no exception specification yet no exceptions can propagate past it.", function);
+
+      return;
+    }
+ 
+  if(res_throwable == NULL_TREE)
+    /* No exceptions can propogate to outside the function. */
+    {
+      if(TREE_VALUE(exceptions) != NULL_TREE)
+        warning(0, "XES: %q+F has an exception specification, yet no exceptions can propagate past it.", function);
+
+      return;
+    }
+
+  if(TREE_TYPE(res_throwable) == NULL_TREE)
+    /* Anything is throwable. */
+    return;
+
+  if(TREE_VALUE(exceptions) == NULL_TREE)
+    return;
+
+  for(spec_node = exceptions; spec_node != NULL_TREE; spec_node = TREE_CHAIN(spec_node))
+    {
+      tree spec_type = TREE_VALUE(spec_node);
+
+      tree list_node;
+      for(list_node = res_throwable; list_node != NULL_TREE; list_node = TREE_CHAIN(list_node))
+        {
+          tree list_type = TREE_TYPE(list_node);
+
+          if(same_or_base_type_p(spec_type, list_type))
+            /* Type may be caught. Don't warn. */
+            break;
+
+          if(same_or_base_type_p(list_type, spec_type))
+            /* Type may be caught here too, since more-derived types are removed from lists. */
+            break;
+        }
+
+      if(list_node == NULL_TREE)
+        {
+          unmatched++;
+
+          if(unmatched == 1)
+            warning(0, "XES: %q+F exception specification includes the following types that are unable to propagate past it:", function);
+
+          if(unmatched <= RES_MAX_XES_EXCEPTIONS_LISTED)
+            inform("XES: %qT.", spec_type);
+        }
+    }
+
+  if(unmatched > RES_MAX_XES_EXCEPTIONS_LISTED)
+    {
+      int unlisted;
+      unlisted = unmatched - RES_MAX_XES_EXCEPTIONS_LISTED;
+      inform("XES: There are %d further unlisted type%s on %q+Fs exception specification that can't propagate past it.", unlisted, (unlisted == 1) ? "" : "s", function);
+    }
+}
+
+/* Called at the start of a try-catch segment if res_check_exception_specification is active.
+   Stores the current throwable and catchable lists and catch type, to be recovered when the try-catch block ends.
+   Parameters:
+     throwable: Pointer to temporary storage for res_throwable.
+     catchable: Pointer to temporary storage for res_catchable.
+     caught: Pointer to temporary storage for res_caught. */
+
+void
+res_on_begin_try(tree* throwable, tree* catchable, tree* caught)
+{
+  /* Temporarily store nested variables. */
+  *throwable = res_throwable;
+  *catchable = res_catchable;
+  *caught = res_caught;
+
+  res_throwable = NULL_TREE;
+  res_catchable = void_type_node;
+  res_caught = void_type_node;
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%stry block begins.", res_intmsg_prefix);
+}
+
+/* Called at the start of a try block if res_check_exception_specification is active.
+   Recovers the throwable list stored on entering the try-block.
+   Parameters:
+     throwable: Pointer to where res_throwable was stored by res_on_begin_try(). */
+
+void
+res_on_end_try(tree* throwable)
+{
+  res_catchable = res_throwable;
+
+  /* Recover nested variable. */
+  res_throwable = *throwable;
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%stry block ends.", res_intmsg_prefix);
+}
+
+/* Called at the end of a try-catch segment if res_check_exception_specification is active.
+   Merges the outer throwable list with what can be thrown out of the try-catch block.
+   Recovers the catchable list and catch type stored on entering the segment.
+   Parameters:
+     catchable: Pointer to where res_catchable was stored by res_on_begin_try().
+     caught: Pointer to where res_caught was stored by res_on_begin_try(). */
+
+void
+res_on_end_handlers(tree* catchable, tree* caught)
+{
+  if(res_catchable == void_type_node)
+    res_catchable = NULL_TREE;
+
+  res_merge(&res_throwable, &res_catchable);
+
+  /* Recover nested variables. */
+  res_catchable = *catchable;
+  res_caught = *caught;
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%stry-catch segment ends.", res_intmsg_prefix);
+}
+
+/* Called at the start of a catch block if res_check_exception_specification is active.
+   Sets res_caught to indicate the type(s) caught.
+   If it's a single type, removes the type from the catchable list.
+   If it's catch(...), it can catch any type that is still in the catchable list.
+   Also checks for -Wxes.
+   Parameters:
+     caught: tcc_type caught, or NULL_TREE for catch(...). */
+
+void
+res_on_begin_catch(tree caught)
+{
+  if(res_catchable == void_type_node)
+    /* This shouldn't happen. */
+    res_catchable = NULL_TREE;
+
+  if(caught == NULL_TREE)
+    /* catch(...) */
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%scatch(...) block begins. ", res_intmsg_prefix);
+
+      if((res_catchable == NULL_TREE) && warn_excessive_exception_specification)
+        warning(0, "XES: catch(...) will never catch any types.");
+
+      res_caught = res_catchable;
+
+      /* Indication for -Wres-cnr */
+      res_catchable = void_type_node;
+    }
+  else
+    /* catch(type) */
+    {
+      bool matched;
+
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%scatch(%qT) block begins.", res_intmsg_prefix, caught);
+
+      res_caught = caught;
+      /* Attempt to remove "caught" from the "res_catchable" list. */
+      matched = res_remove(&res_catchable, caught);
+
+      if((!matched) && warn_excessive_exception_specification)
+        warning(0, "XES: catch(%qT) catches a type never thrown to it.", caught);
+    }
+}
+
+/* Called at the end of a catch block if res_check_exception_specification is active.
+   If ending a catch(...) block, cleans up the TREE_LIST in res_caught. */
+
+void
+res_on_end_catch(void)
+{
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%scatch block ends.", res_intmsg_prefix);
+
+  /* -Wres-cnr */
+  if(warn_res_cnr && (res_catchable == void_type_node))
+    warning(0, "RES: catch(...) has no re-throw.");
+
+  /* Check if res_caught is a TREE_LIST, and if so, empty it. */
+  if(res_caught != NULL_TREE)
+    if(TREE_CODE(res_caught) == TREE_LIST)
+      res_empty(&res_caught);
+}
+
+/* Called on a throw statement if res_check_exception_specification is active.
+   If a type is thrown, adds the thrown type to res_throwable.
+   "type" can be NULL_TREE, indicating a rethrow or throw-terminate.
+   Parameters:
+     expression: The throw expression. */
+
+void
+res_on_throw(tree expression)
+{
+  tree type;
+  location_t loc;
+
+  if(expression == NULL_TREE)
+    type = NULL_TREE;
+  else
+    type = lvalue_type(expression);
+
+  /* <FIXME:Doesn't work.> */
+  /* loc = EXPR_LOCATION(expression); */
+  loc = input_location;
+
+  if(type == NULL_TREE)
+    /* throw; (no type) */
+    res_on_rethrow(NULL_TREE, loc);
+  else
+    /* throw type; */
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sType %qT thrown here.", res_intmsg_prefix, type);
+
+      /* Add "type" to res_throwable. */
+      res_add_type(&res_throwable, type, NULL_TREE, loc);
+    }
+}
+
+/* Called on a throw; statement (with no type) if res_check_exception_specification is active.
+   If outside catch block, or innermost exception block is try {}, this is a throw-terminate. -Wtt will warn here.
+   If innermost exception block is catch(...) block, either adds possibly thrown types to res_throwable, or sets res_throwable to ... (depending on RES_CALCULATE_CATCH_ANY_RETHROW).
+   If innermost exception block is catch(type) block, adds the thrown type to res_throwable.
+   Parameters:
+     thrower: The object rethrowing. <FIXME:Currently NULL_TREE>.
+     loc: The location of the rethrow. */
+
+void
+res_on_rethrow(tree thrower, size_t loc)
+{
+  if(res_caught == void_type_node)
+    {
+      /* -Wtt */
+      if(warn_throw_terminate)
+        warning(0, "TT: Throw-terminate here.");
+    }
+  else
+    /* Innermost exception block is catch. */
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sRe-throw here.", res_intmsg_prefix);
+
+      if(res_caught != NULL_TREE)
+        if(TREE_CODE(res_caught) != TREE_LIST)
+          /* e.g. catch(type) { throw; } */
+          {
+            res_add_type(&res_throwable, res_caught, thrower, loc);
+            return;
+          }
+
+      /* Indication for -Wres-cnr */
+      res_catchable = NULL_TREE;
+
+      /* e.g. catch(...) { throw; } */
+      if(RES_CALCULATE_CATCH_ANY_RETHROW)
+        /* Add all types possibly caught by catch(...) to res_throwable. */
+        res_merge(&res_throwable, &res_caught);
+      else
+        /* Add ... to res_throwable. Empty res_caught. */
+        {
+          res_empty(&res_caught);
+          res_add_any(&res_throwable, thrower, loc);
+        }
+    }
+}
+
+/* Called on a standard function call if res_check_exception_specification is active.
+   Checks blacklists & whitelists from -Wres-wl and -Wres-bl, to see whether to ignore this call.
+   Adds any types thrown by the function to res_throwable.
+   If the function has no exception specification, adds ... .
+   Parameters:
+     function: The FUNCTION_DECL of the called function. */
+
+void
+res_on_call_function(tree function)
+{
+  tree functype;
+  tree exceptions;
+  bool warn;
+  size_t loc = (size_t)input_location;
+  const char* file;
+
+  if(function == NULL_TREE)
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sunknown function called.", res_intmsg_prefix);
+
+      return;
+    }
+
+  /* Retrieve function name string. */
+  file = DECL_SOURCE_FILE(function);
+
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%sfunction %qF called (declared in %s).", res_intmsg_prefix, function, file ? file : "unknown file");
+
+  if(file)
+    /* Check whitelist & blacklist. */
+    warn = res_dwb_file_warnable(file);
+  else
+    /* -Wres-bl-unk. */
+    warn = warn_res_blacklist_unknown;
+
+  if(!warn)
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%sMuting whitelisted %qF.", res_intmsg_prefix, function);
+
+      return;
+    }
+
+  functype = TREE_TYPE(function);
+  exceptions = TYPE_RAISES_EXCEPTIONS(functype);
+  if(exceptions)
+    /* Call to function with exception specification. */
+    {
+      tree list_node;
+      list_node = exceptions;
+      if(TREE_VALUE(list_node) == NULL_TREE)
+        /* Call to function with empty exception specification. */
+        {
+          /* <TEMP> */
+          if(res_intmsg_prefix)
+            warning(0, "%sthrows nothing.", res_intmsg_prefix);
+        }
+      else
+        {
+          /* Step through all thrown types. */
+          while(list_node != NULL_TREE)
+            {
+              tree type;
+              type = TREE_VALUE(list_node);
+              
+              if(type == NULL_TREE)
+                {
+                  /* <TEMP> */
+                  if(res_intmsg_prefix)
+                    warning(0, "%scan throw unknown.", res_intmsg_prefix);
+                }
+              else
+                {
+                  /* <TEMP> */
+                  if(res_intmsg_prefix)
+                    warning(0, "%scan throw %qT.", res_intmsg_prefix, type);
+
+                  /* Add "type" to res_throwable. */
+                  res_add_type(&res_throwable, type, function, loc);
+                }
+
+              list_node = TREE_CHAIN(list_node);
+            }
+        }
+    }
+  else
+    /* Call to function without exception specification. */
+    {
+      /* <TEMP> */
+      if(res_intmsg_prefix)
+        warning(0, "%s%qF can throw anything.", res_intmsg_prefix, function);
+
+      /* Add ... to res_throwable. */
+      res_add_any(&res_throwable, function, loc);
+    }
+}
+
+
+/* Called on a function-pointer function call.
+   FIXME: gcc doesn't store function-pointer exception specifications yet, although it is required to comply with the C++ spec (15.4 -3- : except.spec).
+   Parameters:
+     pointer: The FUNCTION_DECL of the function pointer. */
+
+void
+res_on_call_function_pointer(tree pointer)
+{
+  /* <TEMP> */
+  if(res_intmsg_prefix)
+    warning(0, "%sfunction pointer called. %qD. <FIXME>", res_intmsg_prefix, pointer);
+}
+
+
+/* Adds a type to a type list.
+   Ensures that no types exist that are derived from other types in the list, as catch(type) catches types derived from "type".
+   Parameters:
+     list: Pointer to the list to which the type is to be added.
+     type: Type to be added.
+     thrower: Object throwing the type, such as a FUNCTION_DECL.
+     loc: Where the throwing occurred. */
+
+void
+res_add_type(tree* list, tree type, tree thrower, size_t loc)
+{
+  tree last_node;
+  tree new_tree;
+
+  if((*list) != NULL_TREE)
+    if(TREE_TYPE(*list) == NULL_TREE)
+      /* list is ... */
+      return;
+
+  if(res_prep_add_type(list, type, &last_node))
+    {
+      /* Build the new node. */
+      new_tree = res_make_node(type, thrower, loc);
+
+      /* Attach the new node. */
+      if(last_node == NULL_TREE)
+        *list = new_tree;
+      else
+        TREE_CHAIN(last_node) = new_tree;
+    }
+}
+
+/* Sets a *list to ... .
+   ... is indicated by a 1-node tree whose TREE_TYPE() is NULL_TREE.
+   Parameters:
+     list: Pointer to the list that is becoming ... .
+     thrower: Object throwing the type, such as a FUNCTION_DECL.
+     loc: Where the throwing occurred. */
+
+void
+res_add_any(tree* list, tree thrower, size_t loc)
+{
+  if(*list == NULL_TREE)
+    *list = res_make_node(NULL_TREE, thrower, loc);
+  else
+    {
+      if(TREE_TYPE(*list) != NULL_TREE)
+        {
+          res_empty(list);
+          *list = res_make_node(NULL_TREE, thrower, loc);
+        }
+      /* else tree is already pointing at a function which may throw anything. */
+    }
+}
+
+/* Merges the contents of two type lists, and sets *from to NULL_TREE.
+   If *into is ..., *from is simply emptied.
+   If *from is ..., *into becomes *from.
+   Ensures that no types exist that are derived from other types in the list.
+   Parameters:
+     into: Pointer to the list to add to.
+     from: Pointer to the list to move from. Equal to NULL_TREE on exit. */
+
+void
+res_merge(tree* into, tree* from)
+{
+  tree list_node;
+
+  if((*from) == NULL_TREE)
+    /* from is empty. */
+    return;
+
+  if((*into) == NULL_TREE)
+    /* into is empty. */
+    {
+      *into = *from;
+      *from = NULL_TREE;
+      return;
+    }
+
+  if(TREE_TYPE(*into) == NULL_TREE)
+    /* into = ... */
+    {
+      res_empty(from);
+      return;
+    }
+
+  if(TREE_TYPE(*from) == NULL_TREE)
+    /* from = ... */
+    {
+      res_empty(into);
+      *into = *from;
+      *from = NULL_TREE;
+      return;
+    }
+
+  list_node = *from;
+  /* Step through all types from *from, adding each to *into. */
+  while(list_node)
+    {
+      tree next = TREE_CHAIN(list_node);
+      tree list_type = TREE_TYPE(list_node);
+      tree last_node;
+
+      if(res_prep_add_type(into, list_type, &last_node))
+        {
+          /* Reuse list_node. */
+          TREE_CHAIN(last_node) = list_node;
+          TREE_CHAIN(list_node) = NULL_TREE;
+        }
+      else
+        /* <FIXME>: else delete list_node. */
+        {}
+
+      list_node = next;
+    }
+
+  *from = NULL_TREE;
+}
+
+/* Internal function for res_add_type() and res_merge().
+   Removes all types derived from "type".
+   Exits if "type" or a less-derived type of "type" is found.
+   Parameters:
+     list: Pointer to the list where the type is to be added.
+     type: The type to be added.
+     last: Return-by-reference. Recieves address of the last node in the list. Allows new node to be added to the back. 
+   Return:
+     Indicates whether type needs to be added.
+     false means "type" or a less-derived type of "type" has been found. */
+
+bool
+res_prep_add_type(tree* list, tree type, tree* last)
+{
+  tree list_node;
+  tree prev_node;
+
+  /* Step through list, removing types derived from "type".
+     Exit if "type" or a less-derived base-class of "type" is found. */
+  list_node = *list;
+  prev_node = NULL_TREE;
+  while(list_node != NULL_TREE)
+    {
+      tree list_type = TREE_TYPE(list_node);
+
+      /* Check whether "list_type" is "type", or a less-derived base-class of "type". If so, "type" doesn't need to be added. */
+      if(same_or_base_type_p(list_type, type))
+        return false;
+
+      /* Check whether "type" is a less-derived base-class of "list_type". If so, remove "list_node". */
+      if(same_or_base_type_p(type, list_type))
+        {
+          tree next_node = TREE_CHAIN(list_node);
+          /* <FIXME>: delete list_node */
+
+          if(prev_node == NULL_TREE)
+            *list = next_node;
+          else
+            TREE_CHAIN(prev_node) = next_node;
+
+          list_node = next_node;
+        }
+      else
+        {
+          prev_node = list_node;
+          list_node = TREE_CHAIN(list_node);
+        }
+    }
+
+  *last = prev_node;
+
+  /* "type" needs to be added. */
+  return true;
+}
+
+/* Cleans up a TREE_LIST, deleting all chained nodes.
+   Parameters:
+     list: Pointer to the list to be emptied. */
+
+void
+res_empty(tree* list)
+{
+  tree list_node;
+  list_node = *list;
+  *list = NULL_TREE;
+
+  /* Steps through all types in *list, removing them. */
+  while(list_node != NULL_TREE)
+    {
+      tree next = TREE_CHAIN(list_node);
+      /* <FIXME>: delete list_node */
+      list_node = next;
+    }
+}
+
+/* Attempts to remove "type" or any types derived from "type" from *list.
+   Parameters:
+     list: Pointer to the list to which "type" or its derivatives are to be removed. 
+     type: tcc_type to remove.
+   Return:
+     Indicates whether type is matched. */
+
+bool
+res_remove(tree* list, tree type)
+{
+  tree list_node = *list;
+  tree prev_node = NULL_TREE;
+  bool matched = false;
+
+  if((*list) != NULL_TREE)
+    if(TREE_TYPE(*list) == NULL_TREE)
+      /* List is ... */
+      return true;
+
+  /* Step through all listed types.
+     If a more derived type of "type" is found, remove it.
+     If type or a less derived type of "type" is found, exit. */
+  while(list_node != NULL_TREE)
+    {
+      tree next = TREE_CHAIN(list_node);
+      tree list_type = TREE_TYPE(list_node);
+
+      /* Check whether "type" is "list_type", or a less-derived base-class of "list_type". If so, "list_node" is removed. */
+      if(same_or_base_type_p(type, list_type))
+        {
+          matched = true;
+
+          if(prev_node)
+            TREE_CHAIN(prev_node) = next;
+          else
+            *list = next;
+
+          /* <FIXME>: delete list_node */
+          list_node = next;
+        }
+      else
+        {
+          /* Check whether "list_type" is a less-derived base-class of "type". If so, nothing can be done. */
+          if(same_or_base_type_p(list_type, type))
+            return true;
+
+          prev_node = list_node;
+        }
+
+      list_node = next;
+    }
+
+  return matched;
+}
+
+/* Makes a TREE_LIST node, whose TREE_CHAIN() is set to NULL_TREE.
+   Parameters:
+     type: tcc_type. stored in TREE_TYPE().
+     thrower: stored in TREE_PURPOSE().
+     loc: location where type is thrown. Stored via typecast in TREE_VALUE(). <FIXME:This OK?>
+   Return:
+     The newly built TREE_LIST node. */
+
+tree
+res_make_node(tree type, tree thrower, size_t loc)
+{
+  tree new_tree = tree_cons(thrower, (tree)(void*)loc, NULL_TREE);
+  TREE_TYPE(new_tree) = type;
+
+  return new_tree;
+}
+
+/* Dumps the types in list for debugging, as warnings.
+   One line per type.
+   Parameters:
+     list: The list to output. */
+
+void
+res_warnlist(tree list)
+{
+  if(res_intmsg_prefix == NULL)
+    return;
+
+  if(list == NULL_TREE)
+    warning(0, "%sTypelist: No types.", res_intmsg_prefix);
+  else
+    {
+      tree list_node;
+      for(list_node = list; list_node != NULL_TREE; list_node = TREE_CHAIN(list_node))
+        {
+          tree type;
+          tree thrower;
+          location_t loc;
+          type = TREE_TYPE(list_node);
+          thrower = TREE_PURPOSE(list_node);
+          loc = (location_t)(size_t)TREE_VALUE(list_node);
+
+          if(type == NULL_TREE)
+            {
+              if(thrower == NULL_TREE)
+                warning(0, "%sTypelist: Any type.%H", res_intmsg_prefix, &loc);
+              else
+                warning(0, "%sTypelist: Any type. Thrown by %qD.%H", res_intmsg_prefix, thrower, &loc);
+            }
+          else
+            {
+              if(thrower == NULL_TREE)
+                warning(0, "%sTypelist: %qT.%H", res_intmsg_prefix, type, &loc);
+              else
+                warning(0, "%sTypelist: %qT. Thrown by %qD.%H", res_intmsg_prefix, type, thrower, &loc);
+            }
+        }
+    }
+}
diff -Naur original/gcc-4.3.2/gcc/cp/parser.c res/gcc-4.3.2/gcc/cp/parser.c
--- original/gcc-4.3.2/gcc/cp/parser.c	2008-08-08 00:27:48.000000000 +1200
+++ res/gcc-4.3.2/gcc/cp/parser.c	2008-12-15 19:56:06.000000000 +1300
@@ -37,6 +37,8 @@
 #include "target.h"
 #include "cgraph.h"
 #include "c-common.h"
+/* <[SPH]> */
+#include "res.h"
 
 
 /* The lexer.  */
@@ -13782,6 +13784,7 @@
   ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
   /* Parse the function-body.  */
   cp_parser_function_body (parser);
+
   /* Finish the function body.  */
   finish_function_body (body);
 
@@ -15586,14 +15589,34 @@
 cp_parser_try_block (cp_parser* parser)
 {
   tree try_block;
+  /* <[SPH]> */
+  tree throwable;
+  tree catchable;
+  tree caught;
+
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_begin_try (&throwable, &catchable, &caught);
 
   cp_parser_require_keyword (parser, RID_TRY, "`try'");
   try_block = begin_try_block ();
   cp_parser_compound_statement (parser, NULL, true);
   finish_try_block (try_block);
+
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_end_try (&throwable);
+
   cp_parser_handler_seq (parser);
   finish_handler_sequence (try_block);
 
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_end_handlers (&catchable, &caught);
+
   return try_block;
 }
 
@@ -15666,8 +15689,19 @@
   declaration = cp_parser_exception_declaration (parser);
   finish_handler_parms (declaration, handler);
   cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_begin_catch (HANDLER_TYPE(handler));
+
   cp_parser_compound_statement (parser, NULL, false);
   finish_handler (handler);
+
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_end_catch ();
 }
 
 /* Parse an exception-declaration.
@@ -15750,6 +15784,11 @@
     expression = cp_parser_assignment_expression (parser,
 						  /*cast_p=*/false);
 
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_throw (expression);
+
   return build_throw (expression);
 }
 
@@ -16766,6 +16805,16 @@
   bool saved_in_function_body;
   unsigned saved_num_template_parameter_lists;
 
+  /* <[SPH]> */
+  tree throwable;
+  tree catchable;
+  tree caught;
+
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    /* Processing for -Wres & -Wxes. */
+    res_on_begin_function (&throwable, &catchable, &caught);
+
   saved_in_function_body = parser->in_function_body;
   parser->in_function_body = true;
   /* If the next token is `return', then the code may be trying to
@@ -16823,6 +16872,16 @@
     = saved_num_template_parameter_lists;
   parser->in_function_body = saved_in_function_body;
 
+  /* <[SPH]> */
+  if (res_check_exception_specification)
+    {
+      /* <FIX>:Is there a better way? */
+      tree temp_function_decl = current_function_decl;
+      current_function_decl = fn;
+      res_on_end_function (&throwable, &catchable, &caught, fn);
+      current_function_decl = temp_function_decl;
+    }
+
   return fn;
 }
 
@@ -19366,6 +19425,7 @@
       }
 }
 
+
 /* OpenMP 2.5:
    variable-list:
      identifier
@@ -20455,6 +20515,12 @@
     SET_EXPR_LOCATION (stmt, pragma_tok->location);
 }
 
+
+
+
+
+
+
 /* The parser.  */
 
 static GTY (()) cp_parser *the_parser;
diff -Naur original/gcc-4.3.2/gcc/cp/semantics.c res/gcc-4.3.2/gcc/cp/semantics.c
--- original/gcc-4.3.2/gcc/cp/semantics.c	2008-06-11 18:47:36.000000000 +1200
+++ res/gcc-4.3.2/gcc/cp/semantics.c	2008-12-14 19:56:28.000000000 +1300
@@ -46,6 +46,8 @@
 #include "tree-iterator.h"
 #include "vec.h"
 #include "target.h"
+/* <[SPH]> */
+#include "res.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
@@ -1974,6 +1976,12 @@
       result = build_call_list (TREE_TYPE (result), orig_fn, orig_args);
       KOENIG_LOOKUP_P (result) = koenig_p;
     }
+
+  /* <[SPH]> */
+  if (res_check_exception_specification && (fn != NULL_TREE))
+    /* Processing for -Wres & -Wxes. */
+    res_on_call_function (fn);
+
   return result;
 }
 
diff -Naur original/gcc-4.3.2/gcc/res.h res/gcc-4.3.2/gcc/res.h
--- original/gcc-4.3.2/gcc/res.h	1970-01-01 12:00:00.000000000 +1200
+++ res/gcc-4.3.2/gcc/res.h	2008-12-16 17:45:04.000000000 +1300
@@ -0,0 +1,111 @@
+/* C++ Restrictive Exception Specification (RES) warning mechanic.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+   Free Software Foundation, Inc.
+   Contributed by Simon Hill. (yacwroy@gmail.com)
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* <[SPH]> */
+
+/* Internal warning prefix. NULL = no internal warnings. */
+#define RES_INTMSG_PREFIX "------------------------------------: "
+/* #define RES_INTMSG_PREFIX NULL */
+const char*
+res_intmsg_prefix;
+
+
+
+/* Restrictive Exception Specifiers. */
+
+bool
+res_check_exception_specification;
+
+/* Functions called from gcc standard. */
+void
+res_on_begin_function(tree*, tree*, tree*);
+void
+res_on_end_function(tree*, tree*, tree*, tree);
+void
+res_on_begin_try(tree*, tree*, tree*);
+void
+res_on_end_try(tree*);
+void
+res_on_end_handlers(tree*, tree*);
+void
+res_on_begin_catch(tree);
+void
+res_on_end_catch(void);
+void
+res_on_throw(tree);
+void
+res_on_rethrow(tree, size_t);
+void
+res_on_call_function(tree);
+void
+res_on_call_function_pointer(tree);
+
+/* RES and XES checks. */
+void
+res_check_res(tree function, tree exceptions);
+void
+res_check_xes(tree function, tree exceptions);
+
+/* Internal */
+void
+res_add_type(tree*, tree, tree, size_t);
+void
+res_add_any(tree*, tree, size_t);
+bool
+res_prep_add_type(tree*, tree, tree*);
+void
+res_merge(tree*, tree*);
+void
+res_empty(tree*);
+bool
+res_remove(tree*, tree);
+tree
+res_make_node(tree, tree, size_t);
+void
+res_warnlist(tree);
+
+#define RES_MAX_RES_EXCEPTIONS_LISTED 8
+#define RES_MAX_XES_EXCEPTIONS_LISTED 8
+#define RES_CALCULATE_CATCH_ANY_RETHROW true
+
+
+
+/* Blacklists & Whitelists */
+void
+res_dwb_add_filelist(const char*);
+bool
+res_dwb_file_warnable(const char*);
+
+#define RES_DWB_SYSTEM_DIR "/usr/include/"
+#define RES_DWB_CHECK_USER_PATH true
+#define RES_DWB_CHECK_SYSTEM_PATH false
+#define RES_DWB_CHECK_UNKNOWN_PATH false
+
+#define RES_DWB_FLAG_BLACKLIST (1 << 0)
+#define RES_DWB_FLAG_SYSTEM (1 << 1)
+#define RES_DWB_FLAG_PARTIAL (1 << 2)
+
+#define RES_DWB_CHAR_SEPARATOR ','
+#define RES_DWB_CHAR_BLACKLIST '-'
+#define RES_DWB_CHAR_SYSTEM '^'
+#define RES_DWB_CHAR_PARTIAL '+'
+#define RES_DWB_CHAR_ESCAPE '%'

Attachment: res.txt
Description: Text document

Attachment: test.tgz
Description: GNU Zip compressed data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]