Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 907eccb29a08fe51aa5e5c20aa28f841482b4436)
+++ src/Tuples/TupleAssignment.cc	(revision 4c8621ac0673e269714072f2f0e355df9f6462de)
@@ -42,4 +42,5 @@
 	  private:
 		void match();
+		void handleEmptyTuple( const ResolvExpr::AltList & alts );
 
 		struct Matcher {
@@ -130,4 +131,13 @@
 						}
 						match();
+					} else {
+						// handle empty case specially. It is easy to cause conflicts for tuple assignment when we consider any expression with Tuple type to be a tuple.
+						// Instead, only tuple expressions and expressions with at least 2 results are considered tuples for tuple assignment. This most obviously leaves out the
+						// nullary and unary cases. The unary case is handled nicely by the alternative finder as is. For example, an expression of type [int] will be exploded
+						// into a list of one element (combined with the RHS elements), which will easily allow for intrinsic construction. This seems like a best case scenario anyway,
+						// since intrinsic construction is much simpler from a code-gen perspective than tuple construction is.
+						// This leaves the empty case, which is not easily handled by existing alternative finder logic. Instead, it seems simple enough to hanlde here that if the left
+						// side is an empty tuple, then the right side is allowed to be either an empty tuple or an empty list. Fortunately, these cases are identical when exploded.
+						handleEmptyTuple( *ali );
 					}
 				}
@@ -248,5 +258,5 @@
 		static UniqueName lhsNamer( "__massassign_L" );
 		static UniqueName rhsNamer( "__massassign_R" );
-		assert ( ! lhs.empty() && rhs.size() <= 1);
+		assert( ! lhs.empty() && rhs.size() <= 1 );
 
 		ObjectDecl * rtmp = rhs.size() == 1 ? newObject( rhsNamer, rhs.front().expr ) : nullptr;
@@ -278,4 +288,24 @@
 		}
 	}
+
+	// empty case is okay when right side is also "empty" (empty explosion handles no argument case as well as empty tuple case)
+	void TupleAssignSpotter::handleEmptyTuple( const ResolvExpr::AltList & alts ) {
+		assert( ! alts.empty() );
+		Expression * lhs = alts.front().expr;
+		if ( PointerType * ptrType = dynamic_cast< PointerType * >( lhs->get_result() ) ) {
+			if ( TupleType * tupleType = dynamic_cast< TupleType * >( ptrType->get_base() ) ) {
+				if ( tupleType->size() == 0 ) {
+					ResolvExpr::AltList rhs;
+					explode( std::next(alts.begin(), 1), alts.end(), currentFinder.get_indexer(), back_inserter(rhs) );
+					if ( rhs.empty() ) {
+						// okay, no other case is allowed
+						ResolvExpr::TypeEnvironment compositeEnv;
+						simpleCombineEnvironments( alts.begin(), alts.end(), compositeEnv );
+						currentFinder.get_alternatives().push_front( ResolvExpr::Alternative( new TupleAssignExpr( std::list< Expression * >(), std::list< ObjectDecl * >() ), compositeEnv, ResolvExpr::sumCost( alts ) ) );
+					}
+				}
+			}
+		}
+	}
 } // namespace Tuples
 
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 907eccb29a08fe51aa5e5c20aa28f841482b4436)
+++ src/Tuples/TupleExpansion.cc	(revision 4c8621ac0673e269714072f2f0e355df9f6462de)
@@ -225,4 +225,8 @@
 				decl->get_parameters().push_back( tyParam );
 			}
+			if ( tupleType->size() == 0 ) {
+				// empty structs are not standard C. Add a dummy field to empty tuples to silence warnings when a compound literal Tuple0 is created.
+				decl->get_members().push_back( new ObjectDecl( "dummy", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nullptr ) );
+			}
 			typeMap[mangleName] = decl;
 			addDeclaration( decl );
