Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision f3cc5b6512f55846804a909de3b8735e14b2adef)
+++ src/AST/Expr.cpp	(revision 9b4f3290a76fc499cac978b84cc1ab000bd8d6d0)
@@ -20,4 +20,5 @@
 #include <vector>
 
+#include "Stmt.hpp"
 #include "Type.hpp"
 #include "Common/SemanticError.h"
@@ -25,4 +26,5 @@
 #include "InitTweak/InitTweak.h"   // for getPointerBase
 #include "ResolvExpr/typeops.h"    // for extractResultType
+#include "Tuples/Tuples.h"         // for makeTupleType
 
 namespace ast {
@@ -287,4 +289,90 @@
 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
 
+// --- ConstructorExpr
+
+ConstructorExpr::ConstructorExpr( const CodeLocation & loc, const Expr * call ) 
+: Expr( loc ), callExpr( call ) {
+	// allow resolver to type a constructor used as an expression if it has the same type as its 
+	// first argument
+	assert( callExpr );
+	const Expr * arg = InitTweak::getCallArg( callExpr, 0 );
+	assert( arg );
+	result = arg->result;
+}
+
+// --- CompoundLiteralExpr
+
+CompoundLiteralExpr::CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i )
+: Expr( loc ), init( i ) {
+	assert( t && i );
+	result.set_and_mutate( t )->set_lvalue( true );
+}
+
+// --- TupleExpr
+
+TupleExpr::TupleExpr( const CodeLocation & loc, std::vector<ptr<Expr>> && xs )
+: Expr( loc, Tuples::makeTupleType( xs ) ), exprs( xs ) {}
+
+// --- TupleIndexExpr
+
+TupleIndexExpr::TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i )
+: Expr( loc ), tuple( t ), index( i ) {
+	const TupleType * type = strict_dynamic_cast< const TupleType * >( tuple->result );
+	assertf( type->size() > index, "TupleIndexExpr index out of bounds: tuple size %d, requested "
+		"index %d in expr %s", type->size(), index, toString( tuple ).c_str() );
+	// like MemberExpr, TupleIndexExpr is always an lvalue
+	result.set_and_mutate( type->types[ index ] )->set_lvalue( true );
+}
+
+// --- TupleAssignExpr
+
+TupleAssignExpr::TupleAssignExpr( 
+	const CodeLocation & loc, std::vector<ptr<Expr>> && assigns, 
+	std::vector<ptr<ObjectDecl>> && tempDecls )
+: Expr( loc, Tuples::makeTupleType( assigns ) ), stmtExpr() {
+	// convert internally into a StmtExpr which contains the declarations and produces the tuple of 
+	// the assignments
+	std::list<ptr<Stmt>> stmts;
+	for ( const ObjectDecl * obj : tempDecls ) {
+		stmts.emplace_back( new DeclStmt{ loc, obj } );
+	}
+	TupleExpr * tupleExpr = new TupleExpr{ loc, std::move(assigns) };
+	assert( tupleExpr->result );
+	stmts.emplace_back( new ExprStmt{ loc, tupleExpr } );
+	stmtExpr = new StmtExpr{ loc, new CompoundStmt{ loc, std::move(stmts) } };
+}
+
+// --- StmtExpr
+
+StmtExpr::StmtExpr( const CodeLocation & loc, const CompoundStmt * ss ) 
+: Expr( loc ), stmts( ss ), returnDecls(), dtors() { computeResult(); }
+
+void StmtExpr::computeResult() {
+	assert( stmts );
+	const std::list<ptr<Stmt>> & body = stmts->kids;
+	if ( ! returnDecls.empty() ) {
+		// prioritize return decl for result type, since if a return decl exists, then the StmtExpr 
+		// is currently in an intermediate state where the body will always give a void result type
+		result = returnDecls.front()->get_type();
+	} else if ( ! body.empty() ) {
+		if ( const ExprStmt * exprStmt = body.back().as< ExprStmt >() ) {
+			result = exprStmt->expr->result;
+		}
+	}
+	// ensure a result type exists
+	if ( ! result ) { result = new VoidType{}; }
+}
+
+// --- UniqueExpr
+
+unsigned long long UniqueExpr::nextId = 0;
+
+UniqueExpr::UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i = -1 )
+: Expr( loc, e->result ), id( i ) {
+	assert( expr );
+	if ( id == -1 ) {
+		assert( nextId != -1 );
+		id = nextId++;
+	}
 }
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision f3cc5b6512f55846804a909de3b8735e14b2adef)
+++ src/AST/Expr.hpp	(revision 9b4f3290a76fc499cac978b84cc1ab000bd8d6d0)
@@ -491,5 +491,265 @@
 public:
 	ptr<Expr> inout;
-	ptr<Expr> constraint; 
+	ptr<Expr> constraint;
+	ptr<Expr> operand;
+
+	AsmExpr( const CodeLocation & loc, const Expr * io, const Expr * con, const Expr * op )
+	: Expr( loc ), inout( io ), constraint( con ), operand( op ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	AsmExpr * clone() const override { return new AsmExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// The application of a function to a set of parameters, along with a set of copy constructor 
+/// calls, one for each argument
+class ImplicitCopyCtorExpr final : public Expr {
+public:
+	ptr<ApplicationExpr> callExpr;
+	std::vector<ptr<ObjectDecl>> tempDecls;
+	std::vector<ptr<ObjectDecl>> returnDecls;
+	std::vector<ptr<ObjectDecl>> dtors;
+
+	ImplicitCopyCtorExpr( const CodeLocation& loc, const ApplicationExpr * call )
+	: Expr( loc, call->result ), tempDecls(), returnDecls(), dtors() { assert( call ); }
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ImplicitCopyCtorExpr * clone() const override { return new ImplicitCopyCtorExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// Constructor in expression context, e.g. `int * x = alloc() { 42 };`
+class ConstructorExpr final : public Expr {
+public:
+	ptr<Expr> callExpr;
+
+	ConstructorExpr( const CodeLocation & loc, const Expr * call );
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	ConstructorExpr * clone() const override { return new ConstructorExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A C99 compound literal, e.g. `(MyType){ a, b, c }`
+class CompoundLiteralExpr final : public Expr {
+public:
+	ptr<Init> init;
+
+	CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	CompoundLiteralExpr * clone() const override { return new CompoundLiteralExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A range, e.g. `3 ... 5` or `1~10`
+class RangeExpr final : public Expr {
+public:
+	ptr<Expr> low;
+	ptr<Expr> high;
+
+	RangeExpr( const CodeLocation & loc, const Expr * l, const Expr * h )
+	: Expr( loc ), low( l ), high( h ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	RangeExpr * clone() const override { return new RangeExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A tuple expression before resolution, e.g. `[a, b, c]`
+class UntypedTupleExpr final : public Expr {
+public:
+	std::vector<ptr<Expr>> exprs;
+
+	UntypedTupleExpr( const CodeLocation & loc, std::vector<ptr<Expr>> && xs )
+	: Expr( loc ), exprs( std::move(xs) ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	UntypedTupleExpr * clone() const override { return new UntypedTupleExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A tuple expression after resolution, e.g. `[a, b, c]`
+class TupleExpr final : public Expr {
+public:
+	std::vector<ptr<Expr>> exprs;
+
+	TupleExpr( const CodeLocation & loc, std::vector<ptr<Expr>> && xs );
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TupleExpr * clone() const override { return new TupleExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// An element selection operation on a tuple value, e.g. `t.3` after analysis
+class TupleIndexExpr final : public Expr {
+public:
+	ptr<Expr> tuple;
+	unsigned index;
+
+	TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TupleIndexExpr * clone() const override { return new TupleIndexExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A multiple- or mass-assignment operation, or a tuple ctor/dtor expression. 
+/// multiple-assignment: both sides of the assignment have tuple type, 
+///     e.g. `[a, b, c] = [d, e, f];`
+/// mass-assignment: left-hand side has tuple type and right-hand side does not:
+///     e.g. `[a, b, c] = 42;`
+class TupleAssignExpr final : public Expr {
+public:
+	ptr<StmtExpr> stmtExpr;
+
+	TupleAssignExpr( 
+		const CodeLocation & loc, std::vector<ptr<Expr>> && assigns, 
+		std::vector<ptr<ObjectDecl>> && tempDecls );
+	
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TupleAssignExpr * clone() const override { return new TupleAssignExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// A GCC "statement expression", e.g. `({ int x = 5; x })`
+class StmtExpr final : public Expr {
+public:
+	ptr<CompoundStmt> stmts;
+	std::vector<ptr<ObjectDecl>> returnDecls;  ///< return variable(s) for statement expression
+	std::vector<ptr<Expr>> dtors;              ///< destructor(s) for return variable(s)
+
+	StmtExpr( const CodeLocation & loc, const CompoundStmt * ss );
+
+	/// Set the result type of this StmtExpr based on its body
+	void computeResult();
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	StmtExpr * clone() const override { return new StmtExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// An expression which must only be evaluated once
+class UniqueExpr final : public Expr {
+	static unsigned long long nextId;
+public:
+	ptr<Expr> expr;
+	ptr<ObjectDecl> object;
+	ptr<VariableExpr> var;
+	unsigned long long id;
+
+	UniqueExpr( const CodeLocation & loc, const Expr * e, unsigned long long i = -1 );
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	UniqueExpr * clone() const override { return new UniqueExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// One option for resolving an initializer expression
+struct InitAlternative {
+	ptr<Type> type;
+	ptr<Designation> designation;
+
+	InitAlternative() = default;
+	InitAlternative( const Type * ty, const Designation * des ) : type( ty ), designation( des ) {}
+};
+
+/// Pre-resolution initializer expression
+class UntypedInitExpr final : public Expr {
+public:
+	ptr<Expr> expr;
+	std::vector<InitAlternative> initAlts;
+
+	UntypedInitExpr( const CodeLocation & loc, const Expr * e, std::vector<InitAlternative> && as )
+	: Expr( loc ), expr( e ), initAlts( std::move(as) ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	UntypedInitExpr * clone() const override { return new UntypedInitExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// Post-resolution initializer expression
+class InitExpr final : public Expr {
+public:
+	ptr<Expr> expr;
+	ptr<Designation> designation;
+
+	InitExpr( const CodeLocation & loc, const Expr * e, const Designation * des )
+	: Expr( loc, e->result ), expr( e ), designation( des ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	InitExpr * clone() const override { return new InitExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// Expression containing a deleted identifier.
+/// Internal to resolver.
+class DeletedExpr final : public Expr {
+public:
+	ptr<Expr> expr;
+	readonly<Node> deleteStmt;
+
+	DeletedExpr( const CodeLocation & loc, const Expr * e, const Node * del )
+	: Expr( loc, e->result ), expr( e ), deleteStmt( del ) { assert( expr->result ); }
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	DeletedExpr * clone() const override { return new DeletedExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// Use of a default argument.
+/// Internal to resolver.
+class DefaultArgExpr final : public Expr {
+public:
+	ptr<Expr> expr;
+
+	DefaultArgExpr( const CodeLocation & loc, const Expr * e )
+	: Expr( loc, e->result ), expr( e ) { assert( e->result ); }
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	DefaultArgExpr * clone() const override { return new DefaultArgExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// C11 _Generic expression
+class GenericExpr final : public Expr {
+public:
+	/// One arm of the _Generic expr
+	struct Association {
+		ptr<Type> type;
+		ptr<Expr> expr;
+
+		Association() = default;
+		// default case
+		Association( const Expr * e ) : type(), expr( e ) {}
+		// non-default case
+		Association( const Type * t, const Expr * e ) : type( t ), expr( e ) {}
+	};
+
+	ptr<Expr> control;
+	std::vector<Association> associations;
+
+	GenericExpr( const CodeLocation & loc, const Expr * ctrl, std::vector<Association> && assns )
+	: Expr( loc ), control( ctrl ), associations( std::move(assns) ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	GenericExpr * clone() const override { return new GenericExpr{ *this }; }
+	MUTATE_FRIEND
 };
 
@@ -545,36 +805,34 @@
 inline void increment( const class AsmExpr * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class AsmExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class ConstructorExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class ConstructorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class UntypedValofExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class UntypedValofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class RangeExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class RangeExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class TupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class TupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class TupleIndexExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class TupleIndexExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class TupleAssignExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class TupleAssignExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class StmtExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class StmtExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class UniqueExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class UniqueExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class UntypedInitExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class UntypedInitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class InitExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class InitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class DeletedExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class DeletedExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class DefaultArgExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class DefaultArgExpr * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class GenericExpr * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class GenericExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class ConstructorExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class ConstructorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class RangeExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class RangeExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class TupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class TupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class TupleIndexExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class TupleIndexExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class TupleAssignExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class TupleAssignExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class StmtExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class StmtExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class UniqueExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class UniqueExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class UntypedInitExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class UntypedInitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class InitExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class InitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class DeletedExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class DeletedExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class DefaultArgExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class DefaultArgExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class GenericExpr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class GenericExpr * node, Node::ref_type ref ) { node->decrement(ref); }
 }
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision f3cc5b6512f55846804a909de3b8735e14b2adef)
+++ src/AST/Fwd.hpp	(revision 9b4f3290a76fc499cac978b84cc1ab000bd8d6d0)
@@ -85,5 +85,4 @@
 class ConstructorExpr;
 class CompoundLiteralExpr;
-class UntypedValofExpr;
 class RangeExpr;
 class UntypedTupleExpr;
@@ -267,6 +266,4 @@
 inline void increment( const class CompoundLiteralExpr *, Node::ref_type );
 inline void decrement( const class CompoundLiteralExpr *, Node::ref_type );
-inline void increment( const class UntypedValofExpr *, Node::ref_type );
-inline void decrement( const class UntypedValofExpr *, Node::ref_type );
 inline void increment( const class RangeExpr *, Node::ref_type );
 inline void decrement( const class RangeExpr *, Node::ref_type );
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision f3cc5b6512f55846804a909de3b8735e14b2adef)
+++ src/AST/Type.hpp	(revision 9b4f3290a76fc499cac978b84cc1ab000bd8d6d0)
@@ -23,5 +23,5 @@
 
 #include "CVQualifiers.hpp"
-#include "Decl.hpp"
+#include "Decl.hpp"          // for AggregateDecl subclasses
 #include "Fwd.hpp"
 #include "Node.hpp"          // for Node, ptr
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision f3cc5b6512f55846804a909de3b8735e14b2adef)
+++ src/AST/porting.md	(revision 9b4f3290a76fc499cac978b84cc1ab000bd8d6d0)
@@ -68,4 +68,7 @@
 * prefer `#pragma once` over `#ifdef` guards
 * namespaces that cover entire files don't get indented
+* The general node headers only `#include "Fwd.hpp"` if they can get away with it
+  * Anything that needs definitions goes in the .cpp file
+  * `Type.hpp` includes `Decl.hpp` so that it knows the `AggregateDecl` subclasses for `ReferenceToType::aggr()` overloads
 
 ### Documentation ###
@@ -166,4 +169,19 @@
 * un-defaulted constructor parameter determining `&&` or `||`
 
+`CompoundLiteralExpr`
+* `initializer` => `init`
+
+`RangeExpr`
+* removed `set_low`, `set_high` due to disuse
+
+`TupleIndexExpr`
+* removed `set_tuple`, `set_index` due to disuse
+
+`GenericExpr`
+* `Association::isDefault` removed: `! type` is equivalent
+
+`StmtExpr`
+* `statements` => `stmts`
+
 `Init`
 * `bool maybeConstruct` => `enum ConstructFlag { DoConstruct, MaybeConstruct }`
