Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.598
diff -u -p -r1.598 theme.inc
--- includes/theme.inc	19 May 2010 19:22:24 -0000	1.598
+++ includes/theme.inc	5 Jun 2010 23:51:01 -0000
@@ -764,7 +764,7 @@ function theme($hook, $variables = array
       }
     }
     if (!isset($hooks[$hook])) {
-      watchdog('theme', 'Theme key "@key" not found.', array('@key' => $hook), WATCHDOG_WARNING);
+      trigger_error(t('Theme key "@key" not found.', array('@key' => $hook)));
       return '';
     }
   }
@@ -866,6 +866,13 @@ function theme($hook, $variables = array
     if (function_exists($info['function'])) {
       $output = $info['function']($variables);
     }
+    else {
+      // If a function implementation is registered but doesn't exist, it's
+      // either due to a bug in a module or theme, or module or theme code has
+      // been updated without the theme registry being rebuilt.
+      trigger_error(t('Theme function "@function" not found.', array('@function' => $info['function'])));
+      $output = '';
+    }
   }
   else {
     // Default render function and extension.
@@ -908,6 +915,14 @@ function theme($hook, $variables = array
       $template_file = $info['path'] . '/' . $template_file;
     }
     $output = $render_function($template_file, $variables);
+
+    // A successfully rendered template should always return a string (an empty
+    // string is valid). The template renderer can return literal FALSE to
+    // indicate an error (e.g., if the template file doesn't exist).
+    if ($output === FALSE) {
+      trigger_error(t('Theme template "@template" not found or cannot be rendered.', array('@template' => $template_file)));
+      $output = '';
+    }
   }
 
   // restore path_to_theme()
@@ -1217,7 +1232,14 @@ function theme_render_template($template
   extract($variables, EXTR_SKIP);               // Extract the variables to a local namespace
   ob_start();                                   // Start output buffering
   include DRUPAL_ROOT . '/' . $template_file;   // Include the template file
-  return ob_get_clean();                        // End buffering and return its contents
+  $output = ob_get_clean();                     // End buffering and get its contents
+  // We don't want to call file_exists() unnecessarily, but if nothing was
+  // rendered, it might be due to a missing template file, and we need to flag
+  // that as an error by returning FALSE.
+  if ($output === '' && !file_exists(DRUPAL_ROOT . '/' . $template_file)) {
+    $output = FALSE;
+  }
+  return $output;
 }
 
 /**
