Index: wp-includes/query.php
===================================================================
--- wp-includes/query.php	(revision 19633)
+++ wp-includes/query.php	(working copy)
@@ -1699,8 +1699,8 @@
 		}
 
 		foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
-			if ( 'post_tag' == $taxonomy )
-				continue;	// Handled further down in the $q['tag'] block
+//			if ( 'post_tag' == $taxonomy )
+//				continue;	// Handled further down in the $q['tag'] block
 
 			if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
 				$tax_query_defaults = array(
@@ -1714,18 +1714,57 @@
 
 				$term = $q[$t->query_var];
 
-				if ( strpos($term, '+') !== false ) {
-					$terms = preg_split( '/[+]+/', $term );
-					foreach ( $terms as $term ) {
-						$tax_query[] = array_merge( $tax_query_defaults, array(
-							'terms' => array( $term )
-						) );
-					}
-				} else {
+				// determine the logical operator for each term
+				$term_in_array = $term_and_array = $term_not_in_array = array();
+				foreach( (array) preg_split( '/[,]+/', $term ) as $partial )
+				{
+					switch( $partial{0} )
+					{
+						case '+': // the term is required
+							$term_and_array[] = substr( $partial , 1 );
+							break;
+
+						case '-': // the term is excluded
+							$term_not_in_array[] = substr( $partial , 1 );
+							break;
+
+						default: 
+							if ( strpos( $partial, '+' ) !== false ) // handle old-style AND syntax
+							{
+								$terms = preg_split( '/[+]+/', $partial );
+								foreach ( $terms as $partial )
+									$term_and_array[] = $partial;
+							} else {
+								$term_in_array[] = $partial;
+							}
+					} // end switch $partial{0}
+				}
+
+				// add the above terms to the query array
+				if( ! empty( $term_and_array ))
+				{
 					$tax_query[] = array_merge( $tax_query_defaults, array(
-						'terms' => preg_split( '/[,]+/', $term )
-					) );
+						'terms' => $term_and_array,
+						'operator' => 'AND',
+					));
 				}
+
+				if( ! empty( $term_not_in_array ))
+				{
+					$tax_query[] = array_merge( $tax_query_defaults, array(
+						'terms' => $term_not_in_array,
+						'operator' => 'NOT IN',
+					));
+				}
+
+				if( ! empty( $term_in_array ))
+				{
+					$tax_query[] = array_merge( $tax_query_defaults, array(
+						'terms' => $term_in_array,
+						'operator' => 'IN',
+					));
+				}
+
 			}
 		}
 
@@ -1782,7 +1821,7 @@
 				'include_children' => false
 			);
 		}
-
+/*
 		// Tag stuff
 		if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
 			if ( strpos($q['tag'], ',') !== false ) {
@@ -1855,6 +1894,7 @@
 				'operator' => 'AND'
 			);
 		}
+*/
 
 		$this->tax_query = new WP_Tax_Query( $tax_query );
 	}
