Index: doc/LaTeXmacros/common.tex
===================================================================
--- doc/LaTeXmacros/common.tex	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ doc/LaTeXmacros/common.tex	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -40,4 +40,5 @@
 \newcommand{\CC}{\rm C\kern-.1em\hbox{+\kern-.25em+}\xspace} % CC symbolic name
 \newcommand{\CCeleven}{\rm C\kern-.1em\hbox{+\kern-.25em+}11\xspace} % C++11 symbolic name
+\newcommand{\CCfourteen}{\rm C\kern-.1em\hbox{+\kern-.25em+}14\xspace} % C++14 symbolic name
 \newcommand{\CCseventeen}{\rm C\kern-.1em\hbox{+\kern-.25em+}17\xspace} % C++17 symbolic name
 \newcommand{\Celeven}{C11\xspace}		% C11 symbolic name
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/InitTweak/FixInit.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -232,8 +232,9 @@
 			void handleFirstParam( Expression * firstParam );
 			template< typename... Params >
-			void emit( const Params &... params );
+			void emit( CodeLocation, const Params &... params );
 
 			FunctionDecl * function = 0;
-			std::set< DeclarationWithType * > unhandled, usedUninit;
+			std::set< DeclarationWithType * > unhandled;
+			std::map< DeclarationWithType *, CodeLocation > usedUninit;
 			ObjectDecl * thisParam = 0;
 			bool isCtor = false; // true if current function is a constructor
@@ -336,9 +337,4 @@
 			GenStructMemberCalls warner;
 			acceptAll( translationUnit, warner );
-
-			// visitor doesn't throw so that it can collect all errors
-			if ( ! warner.errors.isEmpty() ) {
-				throw warner.errors;
-			}
 		}
 
@@ -940,8 +936,9 @@
 			ValueGuard< FunctionDecl * > oldFunction( funcDecl );
 			ValueGuard< std::set< DeclarationWithType * > > oldUnhandled( unhandled );
-			ValueGuard< std::set< DeclarationWithType * > > oldUsedUninit( usedUninit );
+			ValueGuard< std::map< DeclarationWithType *, CodeLocation > > oldUsedUninit( usedUninit );
 			ValueGuard< ObjectDecl * > oldThisParam( thisParam );
 			ValueGuard< bool > oldIsCtor( isCtor );
 			ValueGuard< StructDecl * > oldStructDecl( structDecl );
+			errors = SemanticError();  // clear previous errors
 
 			// need to start with fresh sets
@@ -972,8 +969,18 @@
 			// remove the unhandled objects from usedUninit, because a call is inserted
 			// to handle them - only objects that are later constructed are used uninitialized.
-			std::set< DeclarationWithType * > diff;
-			std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ) );
-			for ( DeclarationWithType * member : diff ) {
-				emit( "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", member->get_name(), " used before being constructed" );
+			std::map< DeclarationWithType *, CodeLocation > diff;
+			// need the comparator since usedUninit and unhandled have different types
+			struct comp_t {
+				typedef decltype(usedUninit)::value_type usedUninit_t;
+				typedef decltype(unhandled)::value_type unhandled_t;
+				bool operator()(usedUninit_t x, unhandled_t y) { return x.first < y; }
+				bool operator()(unhandled_t x, usedUninit_t y) { return x < y.first; }
+			} comp;
+			std::set_difference( usedUninit.begin(), usedUninit.end(), unhandled.begin(), unhandled.end(), std::inserter( diff, diff.begin() ), comp );
+			for ( auto p : diff ) {
+				DeclarationWithType * member = p.first;
+				CodeLocation loc = p.second;
+				// xxx - make error message better by also tracking the location that the object is constructed at?
+				emit( loc, "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", member->get_name(), " used before being constructed" );
 			}
 
@@ -1020,9 +1027,12 @@
 							}
 						} catch ( SemanticError & error ) {
-							emit( "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", field->get_name(), " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
+							emit( funcDecl->location, "in ", CodeGen::genPrettyType( function->get_functionType(), function->get_name() ), ", field ", field->get_name(), " not explicitly ", isCtor ? "constructed" : "destructed",  " and no ", isCtor ? "default constructor" : "destructor", " found" );
 						}
 					}
 				}
 				leaveScope();
+			}
+			if (! errors.isEmpty()) {
+				throw errors;
 			}
 		}
@@ -1079,5 +1089,5 @@
 							if ( unhandled.count( memberExpr->get_member() ) ) {
 								// emit a warning because a member was used before it was constructed
-								usedUninit.insert( memberExpr->get_member() );
+								usedUninit.insert( { memberExpr->get_member(), memberExpr->location } );
 							}
 						}
@@ -1089,13 +1099,15 @@
 
 		template< typename Visitor, typename... Params >
-		void error( Visitor & v, const Params &... params ) {
-			v.errors.append( toString( params... ) );
+		void error( Visitor & v, CodeLocation loc, const Params &... params ) {
+			SemanticError err( toString( params... ) );
+			err.set_location( loc );
+			v.errors.append( err );
 		}
 
 		template< typename... Params >
-		void GenStructMemberCalls::emit( const Params &... params ) {
+		void GenStructMemberCalls::emit( CodeLocation loc, const Params &... params ) {
 			// toggle warnings vs. errors here.
 			// warn( params... );
-			error( *this, params... );
+			error( *this, loc, params... );
 		}
 
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/Parser/ExpressionNode.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -254,4 +254,5 @@
 Expression *build_pfieldSel( ExpressionNode *expr_node, Expression *member ) {
 	UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
+	deref->location = expr_node->location;
 	deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
 	UntypedMemberExpr *ret = new UntypedMemberExpr( member, deref );
Index: src/Parser/ParseNode.h
===================================================================
--- src/Parser/ParseNode.h	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/Parser/ParseNode.h	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -134,4 +134,5 @@
 			Expression * p = orig->build();
 			p->set_extension( orig->get_extension() );
+			p->location = orig->location;
 			return p;
 		} else {
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -200,7 +200,8 @@
 		}
 
-		// Central location to handle gcc extension keyword for all expression types.
+		// Central location to handle gcc extension keyword, etc. for all expression types.
 		for ( Alternative &iter: alternatives ) {
 			iter.expr->set_extension( expr->get_extension() );
+			iter.expr->location = expr->location;
 		} // for
 	}
Index: src/SynTree/Declaration.cc
===================================================================
--- src/SynTree/Declaration.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/SynTree/Declaration.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -32,5 +32,5 @@
 
 Declaration::Declaration( const Declaration &other )
-	: name( other.name ), storageClasses( other.storageClasses ), linkage( other.linkage ), uniqueId( other.uniqueId ) {
+	: BaseSyntaxNode( other ), name( other.name ), storageClasses( other.storageClasses ), linkage( other.linkage ), uniqueId( other.uniqueId ) {
 }
 
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/SynTree/Expression.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -33,5 +33,5 @@
 Expression::Expression( Expression *_aname ) : result( 0 ), env( 0 ), argName( _aname ) {}
 
-Expression::Expression( const Expression &other ) : result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), argName( maybeClone( other.get_argName() ) ), extension( other.extension ) {
+Expression::Expression( const Expression &other ) : BaseSyntaxNode( other ), result( maybeClone( other.result ) ), env( maybeClone( other.env ) ), argName( maybeClone( other.get_argName() ) ), extension( other.extension ) {
 }
 
Index: src/SynTree/Initializer.cc
===================================================================
--- src/SynTree/Initializer.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/SynTree/Initializer.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -20,5 +20,5 @@
 
 Initializer::Initializer( bool maybeConstructed ) : maybeConstructed( maybeConstructed ) {}
-Initializer::Initializer( const Initializer & other ) : maybeConstructed( other.maybeConstructed ) {
+Initializer::Initializer( const Initializer & other ) : BaseSyntaxNode( other ), maybeConstructed( other.maybeConstructed ) {
 }
 
Index: src/SynTree/Initializer.h
===================================================================
--- src/SynTree/Initializer.h	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/SynTree/Initializer.h	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -112,4 +112,6 @@
 // ConstructorInit represents an initializer that is either a constructor expression or
 // a C-style initializer.
+// It should not be necessary to create ConstructorInit nodes manually. Instead, set maybeConstructed
+// to true on SingleInit or ListInit constructors if object should be constructed.
 class ConstructorInit : public Initializer {
   public:
Index: src/SynTree/Type.cc
===================================================================
--- src/SynTree/Type.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/SynTree/Type.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -50,5 +50,5 @@
 Type::Type( const Qualifiers &tq, const std::list< Attribute * > & attributes ) : tq( tq ), attributes( attributes ) {}
 
-Type::Type( const Type &other ) : tq( other.tq ) {
+Type::Type( const Type &other ) : BaseSyntaxNode( other ), tq( other.tq ) {
 	cloneAll( other.forall, forall );
 	cloneAll( other.attributes, attributes );
@@ -84,5 +84,5 @@
 		printAll( attributes, os, indent+4 );
 	} // if
-	
+
 	tq.print( os );
 }
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/Tuples/TupleExpansion.cc	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -126,11 +126,12 @@
 		/// given a expression representing the member and an expression representing the aggregate,
 		/// reconstructs a flattened UntypedMemberExpr with the right precedence
-		Expression * reconstructMemberExpr( Expression * member, Expression * aggr ) {
+		Expression * reconstructMemberExpr( Expression * member, Expression * aggr, CodeLocation & loc ) {
 			if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( member ) ) {
 				// construct a new UntypedMemberExpr with the correct structure , and recursively
 				// expand that member expression.
 				MemberTupleExpander expander;
-				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->get_member(), new UntypedMemberExpr( memberExpr->get_aggregate(), aggr->clone() ) );
-
+				UntypedMemberExpr * inner = new UntypedMemberExpr( memberExpr->get_aggregate(), aggr->clone() );
+				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->get_member(), inner );
+				inner->location = newMemberExpr->location = loc;
 				memberExpr->set_member(nullptr);
 				memberExpr->set_aggregate(nullptr);
@@ -139,5 +140,7 @@
 			} else {
 				// not a member expression, so there is nothing to do but attach and return
-				return new UntypedMemberExpr( member, aggr->clone() );
+				UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( member, aggr->clone() );
+				newMemberExpr->location = loc;
+				return newMemberExpr;
 			}
 		}
@@ -152,12 +155,16 @@
 			aggr = new UniqueExpr( aggr );
 			for ( Expression *& expr : tupleExpr->get_exprs() ) {
-				expr = reconstructMemberExpr( expr, aggr );
+				expr = reconstructMemberExpr( expr, aggr, memberExpr->location );
+				expr->location = memberExpr->location;
 			}
 			delete aggr;
+			tupleExpr->location = memberExpr->location;
 			return tupleExpr;
 		} else {
 			// there may be a tuple expr buried in the aggregate
 			// xxx - this is a memory leak
-			return new UntypedMemberExpr( memberExpr->get_member()->clone(), memberExpr->get_aggregate()->acceptMutator( *this ) );
+			UntypedMemberExpr * newMemberExpr = new UntypedMemberExpr( memberExpr->get_member()->clone(), memberExpr->get_aggregate()->acceptMutator( *this ) );
+			newMemberExpr->location = memberExpr->location;
+			return newMemberExpr;
 		}
 	}
Index: src/tests/.expect/memberCtors-ERR1.txt
===================================================================
--- src/tests/.expect/memberCtors-ERR1.txt	(revision 615a0968e86dc63f469d72baac2918969c809f3f)
+++ src/tests/.expect/memberCtors-ERR1.txt	(revision 946bcca6a3c077ba095be8710e19a6c1c7d5f7a4)
@@ -1,2 +1,2 @@
-error: in void ?{}(struct B *b), field a2 used before being constructed
+memberCtors.c:62 error: in void ?{}(struct B *b), field a2 used before being constructed
 make: *** [memberCtors-ERR1] Error 1
