Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/AST/Convert.cpp	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -887,5 +887,5 @@
 		auto expr = visitBaseExpr( node,
 			new AsmExpr(
-				get<Expression>().accept1(node->inout),
+				new std::string(node->inout),
 				get<Expression>().accept1(node->constraint),
 				get<Expression>().accept1(node->operand)
@@ -2258,5 +2258,5 @@
 			new ast::AsmExpr(
 				old->location,
-				GET_ACCEPT_1(inout, Expr),
+				old->inout,
 				GET_ACCEPT_1(constraint, Expr),
 				GET_ACCEPT_1(operand, Expr)
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/AST/Expr.hpp	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -556,9 +556,9 @@
 class AsmExpr final : public Expr {
 public:
-	ptr<Expr> inout;
+	std::string inout;
 	ptr<Expr> constraint;
 	ptr<Expr> operand;
 
-	AsmExpr( const CodeLocation & loc, const Expr * io, const Expr * con, const Expr * op )
+	AsmExpr( const CodeLocation & loc, const std::string & io, const Expr * con, const Expr * op )
 	: Expr( loc ), inout( io ), constraint( con ), operand( op ) {}
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/AST/Pass.impl.hpp	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -1300,5 +1300,4 @@
 			maybe_accept( node, &AsmExpr::result );
 		}
-		maybe_accept( node, &AsmExpr::inout      );
 		maybe_accept( node, &AsmExpr::constraint );
 		maybe_accept( node, &AsmExpr::operand    );
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/AST/Print.cpp	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -1011,5 +1011,5 @@
 		os << "Asm Expression:" << endl;
 		++indent;
-		if ( node->inout ) node->inout->accept( *this );
+		if ( !node->inout.empty() ) os << "[" << node->inout << "] ";
 		if ( node->constraint ) node->constraint->accept( *this );
 		if ( node->operand ) node->operand->accept( *this );
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/CodeGen/CodeGenerator.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -786,12 +786,12 @@
 
 	void CodeGenerator::postvisit( AsmExpr * asmExpr ) {
-		if ( asmExpr->get_inout() ) {
+		if ( !asmExpr->inout.empty() ) {
 			output << "[ ";
-			asmExpr->get_inout()->accept( *visitor );
+			output << asmExpr->inout;
 			output << " ] ";
 		} // if
-		asmExpr->get_constraint()->accept( *visitor );
+		asmExpr->constraint->accept( *visitor );
 		output << " ( ";
-		asmExpr->get_operand()->accept( *visitor );
+		asmExpr->operand->accept( *visitor );
 		output << " )";
 	}
Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/Common/PassVisitor.impl.h	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -2452,5 +2452,4 @@
 
 	indexerScopedAccept( node->result    , *this );
-	maybeAccept_impl   ( node->inout     , *this );
 	maybeAccept_impl   ( node->constraint, *this );
 	maybeAccept_impl   ( node->operand   , *this );
@@ -2464,5 +2463,4 @@
 
 	indexerScopedAccept( node->result    , *this );
-	maybeAccept_impl   ( node->inout     , *this );
 	maybeAccept_impl   ( node->constraint, *this );
 	maybeAccept_impl   ( node->operand   , *this );
@@ -2477,5 +2475,4 @@
 	indexerScopedMutate( node->env       , *this );
 	indexerScopedMutate( node->result    , *this );
-	maybeMutate_impl   ( node->inout     , *this );
 	maybeMutate_impl   ( node->constraint, *this );
 	maybeMutate_impl   ( node->operand   , *this );
Index: src/Common/SemanticError.cc
===================================================================
--- src/Common/SemanticError.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/Common/SemanticError.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -149,21 +149,27 @@
 // Helpers
 namespace ErrorHelpers {
+	Colors colors = Colors::Auto;
+
+	static inline bool with_colors() {
+		return colors == Colors::Auto ? isatty( STDERR_FILENO ) : bool(colors);
+	}
+
 	const std::string & error_str() {
-		static std::string str = isatty( STDERR_FILENO ) ? "\e[31merror:\e[39m " : "error: ";
+		static std::string str = with_colors() ? "\e[31merror:\e[39m " : "error: ";
 		return str;
 	}
 
 	const std::string & warning_str() {
-		static std::string str = isatty( STDERR_FILENO ) ? "\e[95mwarning:\e[39m " : "warning: ";
+		static std::string str = with_colors() ? "\e[95mwarning:\e[39m " : "warning: ";
 		return str;
 	}
 
 	const std::string & bold_ttycode() {
-		static std::string str = isatty( STDERR_FILENO ) ? "\e[1m" : "";
+		static std::string str = with_colors() ? "\e[1m" : "";
 		return str;
 	}
 
 	const std::string & reset_font_ttycode() {
-		static std::string str = isatty( STDERR_FILENO ) ? "\e[0m" : "";
+		static std::string str = with_colors() ? "\e[0m" : "";
 		return str;
 	}
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/Common/SemanticError.h	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -97,4 +97,12 @@
 // Helpers
 namespace ErrorHelpers {
+	enum class Colors {
+		Never = false,
+		Always = true,
+		Auto,
+	};
+
+	extern Colors colors;
+
 	const std::string & error_str();
 	const std::string & warning_str();
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/Concurrency/Keywords.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -59,4 +59,5 @@
 
 		Declaration * postmutate( StructDecl * decl );
+		DeclarationWithType * postmutate( FunctionDecl * decl );
 
 		void handle( StructDecl * );
@@ -77,5 +78,6 @@
 		KeywordCastExpr::Target cast_target;
 
-		StructDecl* type_decl = nullptr;
+		StructDecl   * type_decl = nullptr;
+		FunctionDecl * dtor_decl = nullptr;
 	};
 
@@ -97,5 +99,5 @@
 			"__thrd",
 			"get_thread",
-			"thread keyword requires threads to be in scope, add #include <thread.hfa>",
+			"thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
 			true,
 			KeywordCastExpr::Thread
@@ -129,5 +131,5 @@
 			"__cor",
 			"get_coroutine",
-			"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>",
+			"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
 			true,
 			KeywordCastExpr::Coroutine
@@ -161,5 +163,5 @@
 			"__mon",
 			"get_monitor",
-			"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>",
+			"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
 			false,
 			KeywordCastExpr::Monitor
@@ -284,19 +286,31 @@
 	}
 
+	DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
+		if( !type_decl ) return decl;
+		if( !CodeGen::isDestructor( decl->name ) ) return decl;
+
+		auto params = decl->type->parameters;
+		if( params.size() != 1 ) return decl;
+
+		auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
+		if( !type ) return decl;
+
+		auto stype = dynamic_cast<StructInstType*>( type->base );
+		if( !stype ) return decl;
+		if( stype->baseStruct != type_decl ) return decl;
+
+		if( !dtor_decl ) dtor_decl = decl;
+		return decl;
+	}
+
 	Expression * ConcurrentSueKeyword::postmutate( KeywordCastExpr * cast ) {
 		if ( cast_target == cast->target ) {
 			// convert (thread &)t to (thread_desc &)*get_thread(t), etc.
 			if( !type_decl ) SemanticError( cast, context_error );
-			Expression * arg = cast->arg;
-			cast->arg = nullptr;
-			delete cast;
-			return new CastExpr(
-				UntypedExpr::createDeref(
-					new UntypedExpr( new NameExpr( getter_name ), { arg } )
-				),
-				new ReferenceType(
-					noQualifiers,
-					new StructInstType( noQualifiers, type_decl ) )
-				);
+			if( !dtor_decl ) SemanticError( cast, context_error );
+			assert( cast->result == nullptr );
+			cast->set_result( new ReferenceType( noQualifiers, new StructInstType( noQualifiers, type_decl ) ) );
+			cast->concrete_target.field  = field_name;
+			cast->concrete_target.getter = getter_name;
 		}
 		return cast;
@@ -308,4 +322,5 @@
 
 		if( !type_decl ) SemanticError( decl, context_error );
+		if( !dtor_decl ) SemanticError( decl, context_error );
 
 		FunctionDecl * func = forwardDeclare( decl );
Index: src/ControlStruct/MLEMutator.cc
===================================================================
--- src/ControlStruct/MLEMutator.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/ControlStruct/MLEMutator.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -231,12 +231,10 @@
 
 	Statement *MLEMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
+		// only generate these when needed
+		if( !e.isContUsed() && !e.isBreakUsed() ) return bodyLoop;
+
 		// ensure loop body is a block
-		CompoundStmt *newBody;
-		if ( ! (newBody = dynamic_cast<CompoundStmt *>( bodyLoop )) ) {
-			newBody = new CompoundStmt();
-			newBody->get_kids().push_back( bodyLoop );
-		} // if
-
-		// only generate these when needed
+		CompoundStmt * newBody = new CompoundStmt();
+		newBody->get_kids().push_back( bodyLoop );
 
 		if ( e.isContUsed() ) {
Index: src/GenPoly/Lvalue.cc
===================================================================
--- src/GenPoly/Lvalue.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/GenPoly/Lvalue.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -60,5 +60,5 @@
 		}
 
-		struct ReferenceConversions final : public WithStmtsToAdd {
+		struct ReferenceConversions final : public WithStmtsToAdd, public WithGuards {
 			Expression * postmutate( CastExpr * castExpr );
 			Expression * postmutate( AddressExpr * addrExpr );
@@ -71,4 +71,14 @@
 
 		struct FixIntrinsicResult final : public WithGuards {
+			enum {
+				NoSkip,
+				Skip,
+				SkipInProgress
+			} skip = NoSkip;
+
+			void premutate( AsmExpr * ) { GuardValue( skip ); skip = Skip; }
+			void premutate( ApplicationExpr * ) { GuardValue( skip ); skip = (skip == Skip) ? SkipInProgress : NoSkip; }
+
+
 			Expression * postmutate( ApplicationExpr * appExpr );
 			void premutate( FunctionDecl * funcDecl );
@@ -162,5 +172,5 @@
 
 		Expression * FixIntrinsicResult::postmutate( ApplicationExpr * appExpr ) {
-			if ( isIntrinsicReference( appExpr ) ) {
+			if ( skip != SkipInProgress && isIntrinsicReference( appExpr ) ) {
 				// eliminate reference types from intrinsic applications - now they return lvalues
 				ReferenceType * result = strict_dynamic_cast< ReferenceType * >( appExpr->result );
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/Parser/parser.yy	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Aug  4 21:48:23 2019
-// Update Count     : 4364
+// Last Modified On : Sat Dec  7 10:43:44 2019
+// Update Count     : 4394
 //
 
@@ -211,4 +211,15 @@
 } // forCtrl
 
+KeywordCastExpr::Target Aggregate2Target( DeclarationNode::Aggregate aggr ) {
+	KeywordCastExpr::Target target;
+	switch ( aggr ) {
+	  case DeclarationNode::Coroutine: target = KeywordCastExpr::Coroutine; break;
+	  case DeclarationNode::Monitor: target = KeywordCastExpr::Monitor; break;
+	  case DeclarationNode::Thread: target = KeywordCastExpr::Thread; break;
+	  default: abort();
+	} // switch
+	return target;
+} // Aggregate2Target
+
 
 bool forall = false, yyy = false;						// aggregate have one or more forall qualifiers ?
@@ -365,5 +376,5 @@
 %type<decl> abstract_parameter_declaration
 
-%type<aggKey> aggregate_key
+%type<aggKey> aggregate_key aggregate_data aggregate_control
 %type<decl> aggregate_type aggregate_type_nobody
 
@@ -650,4 +661,6 @@
 	| postfix_expression '.' '[' field_name_list ']'	// CFA, tuple field selector
 		{ $$ = new ExpressionNode( build_fieldSel( $1, build_tuple( $4 ) ) ); }
+	| postfix_expression '.' aggregate_control
+		{ $$ = new ExpressionNode( build_keyword_cast( Aggregate2Target( $3 ), $1 ) ); }
 	| postfix_expression ARROW identifier
 		{ $$ = new ExpressionNode( build_pfieldSel( $1, build_varref( $3 ) ) ); }
@@ -793,13 +806,6 @@
 	| '(' type_no_function ')' cast_expression
 		{ $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
-		// keyword cast cannot be grouped because of reduction in aggregate_key
-	| '(' GENERATOR '&' ')' cast_expression				// CFA
-		{ $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
-	| '(' COROUTINE '&' ')' cast_expression				// CFA
-		{ $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Coroutine, $5 ) ); }
-	| '(' THREAD '&' ')' cast_expression				// CFA
-		{ $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Thread, $5 ) ); }
-	| '(' MONITOR '&' ')' cast_expression				// CFA
-		{ $$ = new ExpressionNode( build_keyword_cast( KeywordCastExpr::Monitor, $5 ) ); }
+	| '(' aggregate_control '&' ')' cast_expression		// CFA
+		{ $$ = new ExpressionNode( build_keyword_cast( Aggregate2Target( $2 ), $5 ) ); }
 		// VIRTUAL cannot be opt because of look ahead issues
 	| '(' VIRTUAL ')' cast_expression					// CFA
@@ -1423,7 +1429,7 @@
 asm_operand:											// GCC
 	string_literal '(' constant_expression ')'
-		{ $$ = new ExpressionNode( new AsmExpr( maybeMoveBuild< Expression >( (ExpressionNode *)nullptr ), $1, maybeMoveBuild< Expression >( $3 ) ) ); }
-	| '[' constant_expression ']' string_literal '(' constant_expression ')'
-		{ $$ = new ExpressionNode( new AsmExpr( maybeMoveBuild< Expression >( $2 ), $4, maybeMoveBuild< Expression >( $6 ) ) ); }
+		{ $$ = new ExpressionNode( new AsmExpr( nullptr, $1, maybeMoveBuild< Expression >( $3 ) ) ); }
+	| '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
+		{ $$ = new ExpressionNode( new AsmExpr( $2, $4, maybeMoveBuild< Expression >( $6 ) ) ); }
 	;
 
@@ -2059,11 +2065,19 @@
 
 aggregate_key:
+	aggregate_data
+	| aggregate_control
+	;
+
+aggregate_data:
 	STRUCT
 		{ yyy = true; $$ = DeclarationNode::Struct; }
 	| UNION
 		{ yyy = true; $$ = DeclarationNode::Union; }
-	| EXCEPTION
+	| EXCEPTION											// CFA
 		{ yyy = true; $$ = DeclarationNode::Exception; }
-	| GENERATOR
+	;
+
+aggregate_control:										// CFA
+	GENERATOR
 		{ yyy = true; $$ = DeclarationNode::Coroutine; }
 	| COROUTINE
@@ -2096,4 +2110,6 @@
 			distInl( $3 );
 		}
+	| INLINE aggregate_control ';'						// CFA
+	   	{ SemanticError( yylloc, "INLINE aggregate control currently unimplemented." ); $$ = nullptr; }
 	| typedef_declaration ';'							// CFA
 	| cfa_field_declaring_list ';'						// CFA, new style field declaration
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -69,4 +69,5 @@
 		void postvisit( CastExpr * castExpr );
 		void postvisit( VirtualCastExpr * castExpr );
+		void postvisit( KeywordCastExpr * castExpr );
 		void postvisit( UntypedMemberExpr * memberExpr );
 		void postvisit( MemberExpr * memberExpr );
@@ -1255,4 +1256,61 @@
 	}
 
+	void AlternativeFinder::Finder::postvisit( KeywordCastExpr * castExpr ) {
+		assertf( castExpr->get_result(), "Cast target should have been set in Validate." );
+		auto ref = dynamic_cast<ReferenceType*>(castExpr->get_result());
+		assert(ref);
+		auto inst = dynamic_cast<StructInstType*>(ref->base);
+		assert(inst);
+		auto target = inst->baseStruct;
+
+		AlternativeFinder finder( indexer, env );
+
+		auto pick_alternatives = [target, this](AltList & found, bool expect_ref) {
+			for(auto & alt : found) {
+				Type * expr = alt.expr->get_result();
+				if(expect_ref) {
+					auto res = dynamic_cast<ReferenceType*>(expr);
+					if(!res) { continue; }
+					expr = res->base;
+				}
+
+				if(auto insttype = dynamic_cast<TypeInstType*>(expr)) {
+					auto td = alt.env.lookup(insttype->name);
+					if(!td) { continue; }
+					expr = td->type;
+				}
+
+				if(auto base = dynamic_cast<StructInstType*>(expr)) {
+					if(base->baseStruct == target) {
+						alternatives.push_back(
+							std::move(alt)
+						);
+					}
+				}
+			}
+		};
+
+		try {
+			// Attempt 1 : turn (thread&)X into (thread_desc&)X.__thrd
+			// Clone is purely for memory management
+			std::unique_ptr<Expression> tech1 { new UntypedMemberExpr(new NameExpr(castExpr->concrete_target.field), castExpr->arg->clone()) };
+
+			// don't prune here, since it's guaranteed all alternatives will have the same type
+			finder.findWithoutPrune( tech1.get() );
+			pick_alternatives(finder.alternatives, false);
+
+			return;
+		} catch(SemanticErrorException & ) {}
+
+		// Fallback : turn (thread&)X into (thread_desc&)get_thread(X)
+		std::unique_ptr<Expression> fallback { UntypedExpr::createDeref( new UntypedExpr(new NameExpr(castExpr->concrete_target.getter), { castExpr->arg->clone() })) };
+		// don't prune here, since it's guaranteed all alternatives will have the same type
+		finder.findWithoutPrune( fallback.get() );
+
+		pick_alternatives(finder.alternatives, true);
+
+		// Whatever happens here, we have no more fallbacks
+	}
+
 	namespace {
 		/// Gets name from untyped member expression (member must be NameExpr)
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/ResolvExpr/Resolver.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -485,7 +485,4 @@
 		visit_children = false;
 		findVoidExpression( asmExpr->operand, indexer );
-		if ( asmExpr->get_inout() ) {
-			findVoidExpression( asmExpr->inout, indexer );
-		} // if
 	}
 
@@ -1365,9 +1362,4 @@
 		asmExpr = ast::mutate_field(
 			asmExpr, &ast::AsmExpr::operand, findVoidExpression( asmExpr->operand, symtab ) );
-
-		if ( asmExpr->inout ) {
-			asmExpr = ast::mutate_field(
-				asmExpr, &ast::AsmExpr::inout, findVoidExpression( asmExpr->inout, symtab ) );
-		}
 
 		return asmExpr;
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/SynTree/Expression.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -527,10 +527,10 @@
 }
 
-AsmExpr::AsmExpr( const AsmExpr & other ) : Expression( other ), inout( maybeClone( other.inout ) ), constraint( maybeClone( other.constraint ) ), operand( maybeClone( other.operand ) ) {}
+AsmExpr::AsmExpr( const AsmExpr & other ) : Expression( other ), inout( other.inout ), constraint( maybeClone( other.constraint ) ), operand( maybeClone( other.operand ) ) {}
 
 
 void AsmExpr::print( std::ostream & os, Indenter indent ) const {
 	os << "Asm Expression: " << std::endl;
-	if ( inout ) inout->print( os, indent+1 );
+	if ( !inout.empty() ) os <<  "[" << inout << "] ";
 	if ( constraint ) constraint->print( os, indent+1 );
 	if ( operand ) operand->print( os, indent+1 );
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/SynTree/Expression.h	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -231,5 +231,11 @@
 	enum Target {
 		Coroutine, Thread, Monitor, NUMBER_OF_TARGETS
-	} target;
+	};
+	struct Concrete {
+		std::string field;
+		std::string getter;
+	};
+	Target target;
+	Concrete concrete_target;
 
 	KeywordCastExpr( Expression * arg, Target target );
@@ -575,20 +581,11 @@
 class AsmExpr : public Expression {
   public:
-	Expression * inout;
+	std::string inout;
 	Expression * constraint;
 	Expression * operand;
 
-	AsmExpr( Expression * inout, Expression * constraint, Expression * operand ) : inout( inout ), constraint( constraint ), operand( operand ) {}
+	AsmExpr( const std::string * _inout, Expression * constraint, Expression * operand ) : inout( _inout ? *_inout : "" ), constraint( constraint ), operand( operand ) { delete _inout; }
 	AsmExpr( const AsmExpr & other );
-	virtual ~AsmExpr() { delete inout; delete constraint; delete operand; };
-
-	Expression * get_inout() const { return inout; }
-	void set_inout( Expression * newValue ) { inout = newValue; }
-
-	Expression * get_constraint() const { return constraint; }
-	void set_constraint( Expression * newValue ) { constraint = newValue; }
-
-	Expression * get_operand() const { return operand; }
-	void set_operand( Expression * newValue ) { operand = newValue; }
+	virtual ~AsmExpr() { delete constraint; delete operand; };
 
 	virtual AsmExpr * clone() const override { return new AsmExpr( * this ); }
Index: src/cfa.make
===================================================================
--- src/cfa.make	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/cfa.make	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -4,6 +4,5 @@
 LTCFACOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=compile $(CFACC) $(DEFS) \
-	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(CFAFLAGS) \
-	$(AM_CFLAGS) $(CFLAGS)
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CFAFLAGS) $(AM_CFLAGS) $(CFAFLAGS) $(CFLAGS)
 
 AM_V_CFA = $(am__v_CFA_@AM_V@)
Index: src/main.cc
===================================================================
--- src/main.cc	(revision aca6a54c0c0604121cda1b4ecf7c0062e40d4553)
+++ src/main.cc	(revision e752e4ec3e790f54e27c6b96ecd3ff3925567ea0)
@@ -407,8 +407,10 @@
 
 
-static const char optstring[] = ":hlLmNnpP:S:twW:D:";
+static const char optstring[] = ":c:ghlLmNnpP:S:twW:D:";
 
 enum { PreludeDir = 128 };
 static struct option long_opts[] = {
+	{ "colors", required_argument, nullptr, 'c' },
+	{ "gdb", no_argument, nullptr, 'g' },
 	{ "help", no_argument, nullptr, 'h' },
 	{ "libcfa", no_argument, nullptr, 'l' },
@@ -422,5 +424,4 @@
 	{ "statistics", required_argument, nullptr, 'S' },
 	{ "tree", no_argument, nullptr, 't' },
-	{ "gdb", no_argument, nullptr, 'g' },
 	{ "", no_argument, nullptr, 0 },					// -w
 	{ "", no_argument, nullptr, 0 },					// -W
@@ -430,19 +431,20 @@
 
 static const char * description[] = {
-	"print help message",								// -h
-	"generate libcfa.c",								// -l
-	"generate line marks",								// -L
-	"do not replace main",								// -m
-	"do not generate line marks",						// -N
-	"do not read prelude",								// -n
+	"diagnostic color: never, always, or auto.",          // -c
+	"wait for gdb to attach",                             // -g
+	"print help message",                                 // -h
+	"generate libcfa.c",                                  // -l
+	"generate line marks",                                // -L
+	"do not replace main",                                // -m
+	"do not generate line marks",                         // -N
+	"do not read prelude",                                // -n
 	"generate prototypes for prelude functions",		// -p
-	"print",											// -P
+	"print",                                              // -P
 	"<directory> prelude directory for debug/nodebug",	// no flag
 	"<option-list> enable profiling information:\n          counters,heap,time,all,none", // -S
-	"building cfa standard lib",									// -t
-	"wait for gdb to attach",									// -g
-	"",													// -w
-	"",													// -W
-	"",													// -D
+	"building cfa standard lib",                          // -t
+	"",                                                   // -w
+	"",                                                   // -W
+	"",                                                   // -D
 }; // description
 
@@ -512,4 +514,13 @@
 	while ( (c = getopt_long( argc, argv, optstring, long_opts, nullptr )) != -1 ) {
 		switch ( c ) {
+		  case 'c':										// diagnostic colors
+			if ( strcmp( optarg, "always" ) == 0 ) {
+				ErrorHelpers::colors = ErrorHelpers::Colors::Always;
+			} else if ( strcmp( optarg, "never" ) == 0 ) {
+				ErrorHelpers::colors = ErrorHelpers::Colors::Never;
+			} else if ( strcmp( optarg, "auto" ) == 0 ) {
+				ErrorHelpers::colors = ErrorHelpers::Colors::Auto;
+			} // if
+			break;
 		  case 'h':										// help message
 			usage( argv );								// no return
