Index: src/GenPoly/Box.cpp
===================================================================
--- src/GenPoly/Box.cpp	(revision c1b0b8fd915f492c94d49c3ed582ddb77a5c8832)
+++ src/GenPoly/Box.cpp	(revision fd4df379a19cd8ddb365ec1ad548df3a82d4efc1)
@@ -673,9 +673,16 @@
 		TypeVarMap const & typeVars,
 		ast::TypeSubstitution const * typeSubs ) {
-	if ( expr->result && isPolyType( expr->result, typeVars, typeSubs ) ) {
-		if ( auto name = expr->func.as<ast::NameExpr>() ) {
-			if ( "*?" == name->name ) {
-				return true;
-			}
+	if ( auto name = expr->func.as<ast::NameExpr>() ) {
+		if ( "*?" == name->name ) {
+			// It's a deref.
+			// Must look under the * (and strip its ptr-ty) because expr's
+			// result could be ar/ptr-decayed.  If expr.inner:T(*)[n], then
+			// expr is a poly deref, even though expr:T*, which is not poly.
+			auto ptrExpr = expr->args.front();
+			auto ptrTy = ptrExpr->result.as<ast::PointerType>();
+			assert(ptrTy); // thing being deref'd must be pointer
+			auto referentTy = ptrTy->base;
+			assert(referentTy);
+			return isPolyType( referentTy, typeVars, typeSubs );
 		}
 	}
@@ -1192,14 +1199,17 @@
 		assert( 2 == expr->args.size() );
 
-		ast::Type const * baseType1 =
-			isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
-		ast::Type const * baseType2 =
-			isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
+		ast::Type const * arg1Ty = expr->args.front()->result;
+		ast::Type const * arg2Ty = expr->args.back()->result;
+
+		// two cases: a[i] with first arg poly ptr, i[a] with second arg poly ptr
+		bool isPoly1 = isPolyPtr( arg1Ty, scopeTypeVars, typeSubs ) != nullptr;
+		bool isPoly2 = isPolyPtr( arg2Ty, scopeTypeVars, typeSubs ) != nullptr;
+
 		// If neither argument is a polymorphic pointer, do nothing.
-		if ( !baseType1 && !baseType2 ) {
+		if ( !isPoly1 && !isPoly2 ) {
 			return expr;
 		}
 		// The arguments cannot both be polymorphic pointers.
-		assert( !baseType1 || !baseType2 );
+		assert( !isPoly1 || !isPoly2 );
 		// (So exactly one of the arguments is a polymorphic pointer.)
 
@@ -1210,16 +1220,22 @@
 		ast::UntypedExpr * ret = new ast::UntypedExpr( location,
 				new ast::NameExpr( location, "?+?" ) );
-		if ( baseType1 ) {
+		if ( isPoly1 ) {
+			assert( arg1Ty );
+			auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
+			assert( arg1TyPtr );
 			auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
 				expr->args.back(),
-				new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
+				new ast::SizeofExpr( location1, deepCopy( arg1TyPtr->base ) ),
 			} );
 			ret->args.push_back( expr->args.front() );
 			ret->args.push_back( multiply );
 		} else {
-			assert( baseType2 );
+			assert( isPoly2 );
+			assert( arg2Ty );
+			auto arg2TyPtr = dynamic_cast<ast::PointerType const * >( arg2Ty );
+			assert( arg2TyPtr );
 			auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
 				expr->args.front(),
-				new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
+				new ast::SizeofExpr( location2, deepCopy( arg2TyPtr->base ) ),
 			} );
 			ret->args.push_back( multiply );
@@ -1234,6 +1250,12 @@
 		assert( 1 == expr->args.size() );
 
+		auto ptrExpr = expr->args.front();
+		auto ptrTy = ptrExpr->result.as<ast::PointerType>();
+		assert(ptrTy); // thing being deref'd must be pointer
+		auto referentTy = ptrTy->base;
+		assert(referentTy);
+
 		// If this isn't for a poly type, then do nothing.
-		if ( !isPolyType( expr->result, scopeTypeVars, typeSubs ) ) {
+		if ( !isPolyType( referentTy, scopeTypeVars, typeSubs ) ) {
 			return expr;
 		}
@@ -1243,4 +1265,8 @@
 		// Fix expression type to remove pointer.
 		ret->result = expr->result;
+		// apply pointer decay
+		if (auto retArTy = ret->result.as<ast::ArrayType>()) {
+			ret->result = new ast::PointerType( retArTy->base );
+		}
 		ret->env = expr->env ? expr->env : ret->env;
 		return ret;
@@ -1291,38 +1317,49 @@
 		return makeIncrDecrExpr(
 			expr->location, expr, baseType, "++?" == varName );
-	// Addition and Subtration Intrinsics:
+	// Addition and Subtraction Intrinsics:
 	} else if ( "?+?" == varName || "?-?" == varName ) {
 		assert( expr->result );
 		assert( 2 == expr->args.size() );
 
-		auto baseType1 =
-			isPolyPtr( expr->args.front()->result, scopeTypeVars, typeSubs );
-		auto baseType2 =
-			isPolyPtr( expr->args.back()->result, scopeTypeVars, typeSubs );
+		ast::Type const * arg1Ty = expr->args.front()->result;
+		ast::Type const * arg2Ty = expr->args.back()->result;
+
+		bool isPoly1 = isPolyPtr( arg1Ty, scopeTypeVars, typeSubs ) != nullptr;
+		bool isPoly2 = isPolyPtr( arg2Ty, scopeTypeVars, typeSubs ) != nullptr;
 
 		CodeLocation const & location = expr->location;
 		CodeLocation const & location1 = expr->args.front()->location;
 		CodeLocation const & location2 = expr->args.back()->location;
-		// LHS op RHS -> (LHS op RHS) / sizeof(LHS)
-		if ( baseType1 && baseType2 ) {
+		// LHS minus RHS -> (LHS minus RHS) / sizeof(LHS)
+		if ( isPoly1 && isPoly2 ) {
+			assert( "?-?" == varName );
+			assert( arg1Ty );
+			auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
+			assert( arg1TyPtr );
 			auto divide = ast::UntypedExpr::createCall( location, "?/?", {
 				expr,
-				new ast::SizeofExpr( location, deepCopy( baseType1 ) ),
+				new ast::SizeofExpr( location, deepCopy( arg1TyPtr->base ) ),
 			} );
 			if ( expr->env ) divide->env = expr->env;
 			return divide;
 		// LHS op RHS -> LHS op (RHS * sizeof(LHS))
-		} else if ( baseType1 ) {
+		} else if ( isPoly1 ) {
+			assert( arg1Ty );
+			auto arg1TyPtr = dynamic_cast<ast::PointerType const * >( arg1Ty );
+			assert( arg1TyPtr );
 			auto multiply = ast::UntypedExpr::createCall( location2, "?*?", {
 				expr->args.back(),
-				new ast::SizeofExpr( location1, deepCopy( baseType1 ) ),
+				new ast::SizeofExpr( location1, deepCopy( arg1TyPtr->base ) ),
 			} );
 			return ast::mutate_field_index(
 				expr, &ast::ApplicationExpr::args, 1, multiply );
 		// LHS op RHS -> (LHS * sizeof(RHS)) op RHS
-		} else if ( baseType2 ) {
+		} else if ( isPoly2 ) {
+			assert( arg2Ty );
+			auto arg2TyPtr = dynamic_cast<ast::PointerType const * >( arg2Ty );
+			assert( arg2TyPtr );
 			auto multiply = ast::UntypedExpr::createCall( location1, "?*?", {
 				expr->args.front(),
-				new ast::SizeofExpr( location2, deepCopy( baseType2 ) ),
+				new ast::SizeofExpr( location2, deepCopy( arg2TyPtr->base ) ),
 			} );
 			return ast::mutate_field_index(
@@ -1588,7 +1625,8 @@
 	/// Change the type of generic aggregate members to char[].
 	void mutateMembers( ast::AggregateDecl * aggr );
-	/// Returns the calculated sizeof expression for type, or nullptr for use
-	/// C sizeof().
+	/// Returns the calculated sizeof/alignof expressions for type, or
+	/// nullptr for use C size/alignof().
 	ast::Expr const * genSizeof( CodeLocation const &, ast::Type const * );
+	ast::Expr const * genAlignof( CodeLocation const &, ast::Type const * );
 	/// Enters a new scope for type-variables,
 	/// adding the type variables from the provided type.
@@ -1613,15 +1651,30 @@
 {}
 
+static ast::Type * polyToMonoTypeRec( CodeLocation const & loc,
+		ast::Type const * ty ) {
+	ast::Type * ret;
+	if ( auto aTy = dynamic_cast<ast::ArrayType const *>( ty ) ) {
+		// recursive case
+		auto monoBase = polyToMonoTypeRec( loc, aTy->base );
+		ret = new ast::ArrayType( monoBase, aTy->dimension,
+			aTy->isVarLen, aTy->isStatic, aTy->qualifiers );
+	} else {
+		// base case
+		auto charType = new ast::BasicType( ast::BasicKind::Char );
+		auto size = new ast::NameExpr( loc,
+			sizeofName( Mangle::mangleType( ty ) ) );
+		ret = new ast::ArrayType( charType, size,
+			ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
+	}
+	return ret;
+}
+
 /// Converts polymorphic type into a suitable monomorphic representation.
-/// Currently: __attribute__(( aligned(8) )) char[size_T];
-ast::Type * polyToMonoType( CodeLocation const & location,
-		ast::Type const * declType ) {
-	auto charType = new ast::BasicType( ast::BasicKind::Char );
-	auto size = new ast::NameExpr( location,
-		sizeofName( Mangle::mangleType( declType ) ) );
-	auto ret = new ast::ArrayType( charType, size,
-		ast::VariableLen, ast::DynamicDim, ast::CV::Qualifiers() );
+/// Simple cases: T -> __attribute__(( aligned(8) )) char[sizeof_T];
+/// Array cases: T[eOut][eIn] ->  __attribute__(( aligned(8) )) char[eOut][eIn][sizeof_T];
+ast::Type * polyToMonoType( CodeLocation const & loc, ast::Type const * ty ) {
+	auto ret = polyToMonoTypeRec( loc, ty );
 	ret->attributes.emplace_back( new ast::Attribute( "aligned",
-		{ ast::ConstantExpr::from_int( location, 8 ) } ) );
+		{ ast::ConstantExpr::from_int( loc, 8 ) } ) );
 	return ret;
 }
@@ -1716,4 +1769,25 @@
 	// Forally, side effects are not safe in this function. But it works.
 	erase_if( mutDecl->attributes, matchAndMove );
+
+	// Change the decl's type.
+	// Upon finishing the box pass, it shall be void*.
+	// At this middle-of-box-pass point, that type is T.
+
+	// example 1
+	// before box:                                  T     t ;
+	// before here:  char _bufxx    [_sizeof_Y1T];  T     t = _bufxx;
+	// after here:   char _bufxx    [_sizeof_Y1T];  T     t = _bufxx;  (no change here - non array case)
+	// after box:    char _bufxx    [_sizeof_Y1T];  void *t = _bufxx;
+
+	// example 2
+	// before box:                                  T     t[42] ;
+	// before here:  char _bufxx[42][_sizeof_Y1T];  T     t[42] = _bufxx;
+	// after here:   char _bufxx[42][_sizeof_Y1T];  T     t     = _bufxx;
+	// after box:    char _bufxx[42][_sizeof_Y1T];  void *t     = _bufxx;
+
+	// Strip all "array of" wrappers
+	while ( auto arrayType = dynamic_cast<ast::ArrayType const *>( mutDecl->type.get() ) ) {
+		mutDecl->type = arrayType->base;
+	}
 
 	mutDecl->init = new ast::SingleInit( decl->location,
@@ -1869,10 +1943,6 @@
 		ast::AlignofExpr const * expr ) {
 	ast::Type const * type = expr->type ? expr->type : expr->expr->result;
-	if ( findGeneric( expr->location, type ) ) {
-		return new ast::NameExpr( expr->location,
-			alignofName( Mangle::mangleType( type ) ) );
-	} else {
-		return expr;
-	}
+	ast::Expr const * gen = genAlignof( expr->location, type );
+	return ( gen ) ? gen : expr;
 }
 
@@ -2095,4 +2165,7 @@
 
 		return true;
+
+	} else if ( auto inst = dynamic_cast<ast::ArrayType const *>( type ) ) {
+		return findGeneric( location, inst->base );
 	}
 	return false;
@@ -2155,6 +2228,20 @@
 		return makeOp( location, "?*?", sizeofBase, dim );
 	} else if ( findGeneric( location, type ) ) {
-		// Generate calculated size for generic type.
+		// Generate reference to _sizeof parameter
 		return new ast::NameExpr( location, sizeofName(
+				Mangle::mangleType( type ) ) );
+	} else {
+		return nullptr;
+	}
+}
+
+ast::Expr const * PolyGenericCalculator::genAlignof(
+		CodeLocation const & location, ast::Type const * type ) {
+	if ( auto * array = dynamic_cast<ast::ArrayType const *>( type ) ) {
+		// alignof array is alignof element
+		return genAlignof( location, array->base );
+	} else if ( findGeneric( location, type ) ) {
+		// Generate reference to _alignof parameter
+		return new ast::NameExpr( location, alignofName(
 				Mangle::mangleType( type ) ) );
 	} else {
