Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Convert.cpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -951,4 +951,10 @@
 	}
 
+	const ast::Expr * visit( const ast::DimensionExpr * node ) override final {
+		auto expr = visitBaseExpr( node, new DimensionExpr( node->name ) );
+		this->node = expr;
+		return nullptr;
+	}
+
 	const ast::Expr * visit( const ast::AsmExpr * node ) override final {
 		auto expr = visitBaseExpr( node,
@@ -2463,12 +2469,7 @@
 
 	virtual void visit( const DimensionExpr * old ) override final {
-		// DimensionExpr gets desugared away in Validate.
-		// As long as new-AST passes don't use it, this cheap-cheerful error
-		// detection helps ensure that these occurrences have been compiled
-		// away, as expected.  To move the DimensionExpr boundary downstream
-		// or move the new-AST translation boundary upstream, implement
-		// DimensionExpr in the new AST and implement a conversion.
-		(void) old;
-		assert(false && "DimensionExpr should not be present at new-AST boundary");
+		this->node = visitBaseExpr( old,
+			new ast::DimensionExpr( old->location, old->name )
+		);
 	}
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Expr.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -604,4 +604,17 @@
 };
 
+class DimensionExpr final : public Expr {
+public:
+	std::string name;
+
+	DimensionExpr( const CodeLocation & loc, std::string name )
+	: Expr( loc ), name( name ) {}
+
+	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	DimensionExpr * clone() const override { return new DimensionExpr{ *this }; }
+	MUTATE_FRIEND
+};
+
 /// A GCC "asm constraint operand" used in an asm statement, e.g. `[output] "=f" (result)`.
 /// https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Machine-Constraints.html#Machine-Constraints
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Fwd.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -84,4 +84,5 @@
 class CommaExpr;
 class TypeExpr;
+class DimensionExpr;
 class AsmExpr;
 class ImplicitCopyCtorExpr;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Pass.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -184,4 +184,5 @@
 	const ast::Expr *             visit( const ast::CommaExpr            * ) override final;
 	const ast::Expr *             visit( const ast::TypeExpr             * ) override final;
+	const ast::Expr *             visit( const ast::DimensionExpr        * ) override final;
 	const ast::Expr *             visit( const ast::AsmExpr              * ) override final;
 	const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) override final;
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Pass.impl.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -575,10 +575,9 @@
 			__pass::symtab::addId( core, 0, func );
 			if ( __visit_children() ) {
-				// parameter declarations
+				maybe_accept( node, &FunctionDecl::type_params );
+				maybe_accept( node, &FunctionDecl::assertions );
 				maybe_accept( node, &FunctionDecl::params );
 				maybe_accept( node, &FunctionDecl::returns );
-				// type params and assertions
-				maybe_accept( node, &FunctionDecl::type_params );
-				maybe_accept( node, &FunctionDecl::assertions );
+				maybe_accept( node, &FunctionDecl::type );
 				// First remember that we are now within a function.
 				ValueGuard< bool > oldInFunction( inFunction );
@@ -1522,4 +1521,18 @@
 
 //--------------------------------------------------------------------------
+// DimensionExpr
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::DimensionExpr * node ) {
+	VISIT_START( node );
+
+	if ( __visit_children() ) {
+		guard_symtab guard { *this };
+		maybe_accept( node, &DimensionExpr::result );
+	}
+
+	VISIT_END( Expr, node );
+}
+
+//--------------------------------------------------------------------------
 // AsmExpr
 template< typename core_t >
@@ -1859,5 +1872,5 @@
 
 	if ( __visit_children() ) {
-		// xxx - should PointerType visit/mutate dimension?
+		maybe_accept( node, &PointerType::dimension );
 		maybe_accept( node, &PointerType::base );
 	}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Pass.proto.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -26,4 +26,7 @@
 
 struct PureVisitor;
+
+template<typename node_t>
+node_t * deepCopy( const node_t * localRoot );
 
 namespace __pass {
@@ -396,5 +399,7 @@
 		static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
 			ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
-			fwd->params = decl->params;
+			for ( const auto & param : decl->params ) {
+				fwd->params.push_back( deepCopy( param.get() ) );
+			}
 			core.symtab.addStruct( fwd );
 		}
@@ -405,6 +410,8 @@
 		template<typename core_t>
 		static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
-			UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
-			fwd->params = decl->params;
+			ast::UnionDecl * fwd = new ast::UnionDecl( decl->location, decl->name );
+			for ( const auto & param : decl->params ) {
+				fwd->params.push_back( deepCopy( param.get() ) );
+			}
 			core.symtab.addUnion( fwd );
 		}
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Print.cpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -1101,4 +1101,11 @@
 	}
 
+	virtual const ast::Expr * visit( const ast::DimensionExpr * node ) override final {
+		os << "Type-Sys Value: " << node->name;
+		postprint( node );
+
+		return node;
+	}
+
 	virtual const ast::Expr * visit( const ast::AsmExpr * node ) override final {
 		os << "Asm Expression:" << endl;
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 92538ab6b62a97cccbb9045dcd6004887dec9529)
+++ src/AST/Visitor.hpp	(revision 365c8dcbd76a5d6cafc342a140f686a573523fea)
@@ -76,4 +76,5 @@
     virtual const ast::Expr *             visit( const ast::CommaExpr            * ) = 0;
     virtual const ast::Expr *             visit( const ast::TypeExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::DimensionExpr        * ) = 0;
     virtual const ast::Expr *             visit( const ast::AsmExpr              * ) = 0;
     virtual const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) = 0;
