Index: doc/generic_types/evaluation/.gitignore
===================================================================
--- doc/generic_types/evaluation/.gitignore	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/.gitignore	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,8 +1,6 @@
 c-bench
 cpp-bench
+cpp-vbench
 cfa-bench
-c2-bench
-cpp2-bench
-cfa2-bench
 *.o
 *.d
Index: doc/generic_types/evaluation/Makefile
===================================================================
--- doc/generic_types/evaluation/Makefile	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/Makefile	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,8 +1,10 @@
 CFA = my-cfa
 DEPFLAGS = -MMD -MP
+CFLAGS = -O2 -flto
+CXXFLAGS = $(CFLAGS) --std=c++14
 
-.PHONY: all clean distclean bench
+.PHONY: all clean distclean run-c run-cpp run-cfa run
 
-all: c-bench cpp-bench cfa-bench c2-bench cpp2-bench cfa2-bench
+all: c-bench cpp-bench cfa-bench
 
 # rewrite object generation to auto-determine deps
@@ -13,77 +15,68 @@
 c-%.o : c-%.c
 c-%.o : c-%.c c-%.d
-	$(COMPILE.c) -O0 $(OUTPUT_OPTION) -c $<
+	$(COMPILE.c) $(OUTPUT_OPTION) -c $<
 
 cpp-%.o : cpp-%.cpp
 cpp-%.o : cpp-%.cpp cpp-%.d
-	$(COMPILE.cpp) -O0 $(OUTPUT_OPTION) -c $<
+	$(COMPILE.cpp) $(OUTPUT_OPTION) -c $<
 
 cfa-%.o : cfa-%.c
 cfa-%.o : cfa-%.c cfa-%.d
-	$(COMPILE.cfa) -O0 $(OUTPUT_OPTION) -c $<
-
-c2-%.o : c-%.c
-c2-%.o : c-%.c c-%.d
-	$(COMPILE.c) -O2 $(OUTPUT_OPTION) -c $<
-
-cpp2-%.o : cpp-%.cpp
-cpp2-%.o : cpp-%.cpp cpp-%.d
-	$(COMPILE.cpp) -O2 $(OUTPUT_OPTION) -c $<
-
-cfa2-%.o : cfa-%.c
-cfa2-%.o : cfa-%.c cfa-%.d
-	$(COMPILE.cfa) -O2 $(OUTPUT_OPTION) -c $<
+	$(COMPILE.cfa) $(OUTPUT_OPTION) -c $<
 
 COBJS = c-stack.o
 CPPOBJS = 
+CPPVOBJS = cpp-vstack.o
 CFAOBJS = cfa-stack.o
-C2OBJS = $(patsubst c-%,c2-%, $(COBJS))
-CPP2OBJS = $(patsubst cpp-%,cpp2-%, $(CPPOBJS))
-CFA2OBJS = $(patsubst cfa-%,cfa2-%, $(CFAOBJS))
 
 c-bench: c-bench.c c-bench.d $(COBJS)
-	$(COMPILE.c) -O0 -o $@ $< $(COBJS) $(LDFLAGS)
+	$(COMPILE.c) -o $@ $< $(COBJS) $(LDFLAGS)
 
 cpp-bench: cpp-bench.cpp cpp-bench.d $(CPPOBJS)
-	$(COMPILE.cpp) -O0 -o $@ $< $(CPPOBJS) $(LDFLAGS)
+	$(COMPILE.cpp) -o $@ $< $(CPPOBJS) $(LDFLAGS)
+
+cpp-vbench: cpp-vbench.cpp cpp-vbench.d $(CPPVOBJS)
+	$(COMPILE.cpp) -o $@ $< $(CPPVOBJS) $(LDFLAGS)
 
 cfa-bench: cfa-bench.c cfa-bench.d $(CFAOBJS)
-	$(COMPILE.cfa) -O0 -o $@ $< $(CFAOBJS) $(LDFLAGS)
-
-c2-bench: c-bench.c c-bench.d $(C2OBJS)
-	$(COMPILE.c) -O2 -o $@ $< $(C2OBJS) $(LDFLAGS)
-
-cpp2-bench: cpp-bench.cpp cpp-bench.d $(CPP2OBJS)
-	$(COMPILE.cpp) -O2 -o $@ $< $(CPP2OBJS) $(LDFLAGS)
-
-cfa2-bench: cfa-bench.c cfa-bench.d $(CFA2OBJS)
-	$(COMPILE.cfa) -O2 -o $@ $< $(CFA2OBJS) $(LDFLAGS)
+	$(COMPILE.cfa) -o $@ $< $(CFAOBJS) $(LDFLAGS)
 
 clean:
 	-rm $(COBJS) c-bench
 	-rm $(CPPOBJS) cpp-bench
+	-rm $(CPPVOBJS) cpp-vbench
 	-rm $(CFAOBJS) cfa-bench
-	-rm $(C2OBJS) c2-bench
-	-rm $(CPP2OBJS) cpp2-bench
-	-rm $(CFA2OBJS) cfa2-bench
 
 distclean: clean
 	-rm $(COBJS:.o=.d) c-bench.d
 	-rm $(CPPOBJS:.o=.d) cpp-bench.d
+	-rm $(CPPVOBJS:.o=.d) cpp-vbench.d
 	-rm $(CFAOBJS:.o=.d) cfa-bench.d
 
-bench: c-bench cpp-bench cfa-bench c2-bench cpp2-bench cfa2-bench
+run-c: c-bench
 	@echo '## C ##'
 	@./c-bench
+	@printf 'source_size:\t%7d lines\n' `cat c-bench.c bench.h c-stack.h c-stack.c | wc -l`
+	@printf 'binary_size:\t%7d bytes\n' `wc -c < c-bench`
+
+run-cfa: cfa-bench
+	@echo '## Cforall ##'
+	@./cfa-bench
+	@printf 'source_size:\t%7d lines\n' `cat cfa-bench.c bench.h cfa-stack.h cfa-stack.c | wc -l`
+	@printf 'binary_size:\t%7d bytes\n' `wc -c < cfa-bench`
+
+run-cpp: cpp-bench
 	@echo '## C++ ##'
 	@./cpp-bench
-	@echo '## Cforall ##'
-	@./cfa-bench
-	@echo '## C -O2 ##'
-	@./c2-bench
-	@echo '## C++ -O2 ##'
-	@./cpp2-bench
-	@echo '## Cforall -O2 ##'
-	@./cfa2-bench
+	@printf 'source_size:\t%7d lines\n' `cat cpp-bench.cpp bench.hpp cpp-stack.hpp | wc -l`
+	@printf 'binary_size:\t%7d bytes\n' `wc -c < cpp-bench`
+
+run-cppv: cpp-vbench
+	@echo '## C++ virtual ##'
+	@./cpp-vbench
+	@printf 'source_size:\t%7d lines\n' `cat cpp-vbench.cpp bench.hpp object.hpp cpp-vstack.hpp cpp-vstack.cpp | wc -l`
+	@printf 'binary_size:\t%7d bytes\n' `wc -c < cpp-vbench`
+
+run: run-c run-cfa run-cpp run-cppv
 
 # so make doesn't fail without dependency files
Index: doc/generic_types/evaluation/bench.h
===================================================================
--- doc/generic_types/evaluation/bench.h	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/bench.h	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,6 +1,9 @@
+#pragma once
+
 #include <stdio.h>
 #include <time.h>
 
-#define N 200000000
+ #define N 100000000
+ 
 
 long ms_between(clock_t start, clock_t end) {
@@ -9,10 +12,10 @@
 
 #define TIMED(name, code) { \
-	clock_t start, end; \
-	start = clock(); \
+	volatile clock_t _start, _end; \
+	_start = clock(); \
 	code \
-	end = clock(); \
-	printf("%s:\t%7ld ms\n", name, ms_between(start, end)); \
+	_end = clock(); \
+	printf("%s:\t%7ld ms\n", name, ms_between(_start, _end)); \
 }
 
-#define REPEAT_TIMED(name, code) TIMED( name, for (int i = 0; i < N; ++i) { code } )
+#define REPEAT_TIMED(name, code) TIMED( name, for (int _i = 0; _i < N; ++_i) { code } )
Index: doc/generic_types/evaluation/bench.hpp
===================================================================
--- doc/generic_types/evaluation/bench.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/bench.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <iomanip>
+#include <iostream>
+#include <time.h>
+
+ #define N 100000000
+ 
+
+long ms_between(clock_t start, clock_t end) {
+	return (end - start) / (CLOCKS_PER_SEC / 1000);
+}
+
+#define TIMED(name, code) { \
+	volatile clock_t _start, _end; \
+	_start = clock(); \
+	code \
+	_end = clock(); \
+	std::cout << name << ":\t" << std::setw(7) << ms_between(_start, _end) << std::setw(0) << " ms" << std::endl; \
+}
+
+#define REPEAT_TIMED(name, code) TIMED( name, for (int _i = 0; _i < N; ++_i) { code } )
Index: doc/generic_types/evaluation/c-bench.c
===================================================================
--- doc/generic_types/evaluation/c-bench.c	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/c-bench.c	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -2,4 +2,10 @@
 #include "bench.h"
 #include "c-stack.h"
+
+void* copy_int( void* p ) {
+	int* q = malloc(sizeof(int));
+	*q = *(int*)p;
+	return q;
+}
 
 int main(int argc, char** argv) {
@@ -7,5 +13,4 @@
 
 	struct stack s = new_stack();
-
 	REPEAT_TIMED( "push_int",
 		int* x = malloc(sizeof(int));
@@ -14,4 +19,18 @@
 	)
 
-	clear_stack(&s);
+	struct stack t;
+	TIMED( "copy_int",
+		copy_stack(&t, &s, copy_int);
+	)
+
+	TIMED( "clear_int",
+		clear_stack(&s);
+	)
+
+	int sum;
+	REPEAT_TIMED( "pop_int", 
+		int* x = pop_stack(&t);
+		sum += *x;
+		free(x);
+	)
 }
Index: doc/generic_types/evaluation/c-stack.c
===================================================================
--- doc/generic_types/evaluation/c-stack.c	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/c-stack.c	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -11,4 +11,16 @@
 }
 
+void copy_stack(struct stack* s, struct stack* t, void* (*copy)(void*)) {
+	struct stack_node** crnt = &s->head;
+	struct stack_node* next = t->head;
+	while ( next ) {
+		*crnt = malloc(sizeof(struct stack_node));
+		**crnt = (struct stack_node){ copy(next->value) };
+		crnt = &(*crnt)->next;
+		next = next->next;
+	}
+	*crnt = 0;
+}
+
 void clear_stack(struct stack* s) {
 	struct stack_node* next = s->head;
@@ -19,4 +31,5 @@
 		free(crnt);
 	}
+	s->head = NULL;
 }
 
Index: doc/generic_types/evaluation/c-stack.h
===================================================================
--- doc/generic_types/evaluation/c-stack.h	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/c-stack.h	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,2 +1,4 @@
+#pragma once
+
 struct stack_node;
 
@@ -7,4 +9,6 @@
 struct stack new_stack();
 
+void copy_stack(struct stack* dst, struct stack* src, void* (*copy)(void*));
+
 void clear_stack(struct stack* s);
 
Index: doc/generic_types/evaluation/cfa-bench.c
===================================================================
--- doc/generic_types/evaluation/cfa-bench.c	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/cfa-bench.c	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -7,7 +7,20 @@
 
 	stack(int) s;
-
 	REPEAT_TIMED( "push_int",
 		push( &s, rand() );
 	)
+
+	stack(int) t;
+	TIMED( "copy_int", 
+		t = s;
+	)
+
+	TIMED( "clear_int", 
+		clear( &s );
+	)
+
+	int sum;
+	REPEAT_TIMED( "pop_int", 
+		sum += pop( &t );
+	)
 }
Index: doc/generic_types/evaluation/cfa-stack.c
===================================================================
--- doc/generic_types/evaluation/cfa-stack.c	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/cfa-stack.c	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,2 +1,3 @@
+#include <assert>
 #include <stdlib>
 #include "cfa-stack.h"
@@ -8,14 +9,40 @@
 
 forall(otype T) void ?{}(stack(T)* s) {
-	?{}( &s->head, 0 );
+	(&s->head){ 0 };
+}
+
+forall(otype T) void copy(stack(T)* s, stack(T)* t) {
+	stack_node(T)** crnt = &s->head;
+	stack_node(T)* next = t->head;
+	while ( next ) {
+		*crnt = ((stack_node(T)*)malloc()){ next->value };
+		stack_node(T)* acrnt = *crnt;
+		crnt = &acrnt->next;
+		next = next->next;
+	}
+	*crnt = 0;
+}
+
+forall(otype T) void ?{}(stack(T)* s, stack(T) t) {
+	stack_node(T)** crnt = &s->head;
+	stack_node(T)* next = t.head;
+	while ( next ) {
+		*crnt = ((stack_node(T)*)malloc()){ next->value };
+		stack_node(T)* acrnt = *crnt;
+		crnt = &acrnt->next;
+		next = next->next;
+	}
+	*crnt = 0;
+}
+
+forall(otype T) stack(T) ?=?(stack(T)* s, stack(T) t) {
+	if ( s->head == t.head ) return *s;
+	clear(s);
+	s{ t };
+	return *s;
 }
 
 forall(otype T) void ^?{}(stack(T)* s) {
-	stack_node(T)* next = s->head;
-	while ( next ) {
-		stack_node(T)* crnt = next;
-		next = crnt->next;
-		delete(crnt);
-	}
+	clear(s);
 }
 
@@ -35,2 +62,12 @@
 	return x;
 }
+
+forall(otype T) void clear(stack(T)* s) {
+	stack_node(T)* next = s->head;
+	while ( next ) {
+		stack_node(T)* crnt = next;
+		next = crnt->next;
+		delete(crnt);
+	}
+	s->head = 0;
+}
Index: doc/generic_types/evaluation/cfa-stack.h
===================================================================
--- doc/generic_types/evaluation/cfa-stack.h	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/cfa-stack.h	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,2 +1,4 @@
+#pragma once
+
 forall(otype T) struct stack_node;
 
@@ -7,4 +9,8 @@
 forall(otype T) void ?{}(stack(T)* s);
 
+forall(otype T) void ?{}(stack(T)* s, stack(T) t);
+
+forall(otype T) stack(T) ?=?(stack(T)* s, stack(T) t);
+
 forall(otype T) void ^?{}(stack(T)* s);
 
@@ -14,2 +20,4 @@
 
 forall(otype T) T pop(stack(T)* s);
+
+forall(otype T) void clear(stack(T)* s);
Index: doc/generic_types/evaluation/cpp-bench.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-bench.cpp	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ doc/generic_types/evaluation/cpp-bench.cpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include "bench.h"
-#include "cpp-stack.h"
+#include "bench.hpp"
+#include "cpp-stack.hpp"
 
 int main(int argc, char** argv) {
@@ -7,7 +7,20 @@
 
 	stack<int> s;
-
 	REPEAT_TIMED( "push_int",
 		s.push( rand() );
 	)
+
+	stack<int> t;
+	TIMED( "copy_int", 
+		t = s;
+	)
+
+	TIMED( "clear_int", 
+		s.clear();
+	)
+
+	int sum;
+	REPEAT_TIMED( "pop_int",
+		sum += t.pop();
+	)
 }
Index: c/generic_types/evaluation/cpp-stack.h
===================================================================
--- doc/generic_types/evaluation/cpp-stack.h	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ 	(revision )
@@ -1,40 +1,0 @@
-#include <utility>
-
-template<typename T> class stack {
-	struct node {
-		T value;
-		node* next;
-
-		node( T&& v, node* n ) : value(std::move(v)), next(n) {}
-	};
-	
-	node* head;
-
-public:
-	stack() : head(nullptr) {}
-
-	~stack() {
-		node* next = head;
-		while ( next ) {
-			node* crnt = next;
-			next = crnt->next;
-			delete crnt;
-		}
-	}
-
-	bool empty() const {
-		return head == nullptr;
-	}
-
-	void push(T&& value) {
-		head = new node{ std::move(value), head };
-	}
-
-	T pop() {
-		node* n = head;
-		head = n->next;
-		T x = std::move(n->value);
-		delete n;
-		return x;
-	}
-};
Index: doc/generic_types/evaluation/cpp-stack.hpp
===================================================================
--- doc/generic_types/evaluation/cpp-stack.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/cpp-stack.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <utility>
+
+template<typename T> class stack {
+	struct node {
+		T value;
+		node* next;
+
+		node( T& v ) : value(v), next(nullptr) {}
+		node( T&& v, node* n ) : value(std::move(v)), next(n) {}
+	};
+	
+	node* head;
+
+	void copy(const stack<T>& o) {
+		node** crnt = &head;
+		node* next = o.head;
+		while ( next ) {
+			*crnt = new node{ next->value };
+			crnt = &(*crnt)->next;
+			next = next->next;
+		}
+		*crnt = nullptr;
+	}
+
+public:
+	void clear() {
+		node* next = head;
+		while ( next ) {
+			node* crnt = next;
+			next = crnt->next;
+			delete crnt;
+		}
+	}
+
+	stack() : head(nullptr) {}
+
+	stack(const stack<T>& o) { copy(o); }
+
+	stack(stack<T>&& o) : head(o.head) { o.head = nullptr; }
+
+	~stack() { clear(); }
+
+	stack& operator= (const stack<T>& o) {
+		if ( this == &o ) return *this;
+		clear();
+		copy(o);
+		return *this;
+	}
+
+	stack& operator= (stack<T>&& o) {
+		if ( this == &o ) return *this;
+		head = o.head;
+		o.head = nullptr;
+		return *this;
+	}
+
+	bool empty() const {
+		return head == nullptr;
+	}
+
+	void push(T&& value) {
+		head = new node{ std::move(value), head };
+	}
+
+	T pop() {
+		node* n = head;
+		head = n->next;
+		T x = std::move(n->value);
+		delete n;
+		return x;
+	}
+};
Index: doc/generic_types/evaluation/cpp-vbench.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-vbench.cpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/cpp-vbench.cpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include "bench.hpp"
+#include "cpp-vstack.hpp"
+
+int main(int argc, char** argv) {
+	srand(20171025);
+
+	stack s;
+	REPEAT_TIMED( "push_int",
+		s.push( std::make_unique<integer>( rand() ) );
+	)
+
+	stack t;
+	TIMED( "copy_int", 
+		t = s;
+	)
+
+	TIMED( "clear_int", 
+		s.clear();
+	)
+
+	integer sum;
+	REPEAT_TIMED( "pop_int",
+		sum += t.pop()->as<integer>();
+	)
+}
Index: doc/generic_types/evaluation/cpp-vstack.cpp
===================================================================
--- doc/generic_types/evaluation/cpp-vstack.cpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/cpp-vstack.cpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,65 @@
+#include "cpp-vstack.hpp"
+
+#include <utility>
+
+stack::node::node( const object& v ) : value( v.new_copy() ), next( nullptr ) {}
+
+stack::node::node( std::unique_ptr<object>&& v, node* n ) : value( std::move(v) ), next( n ) {}
+
+void stack::copy(const stack& o) {
+	node** crnt = &head;
+	node* next = o.head;
+	while ( next ) {
+		*crnt = new node{ *next->value };
+		crnt = &(*crnt)->next;
+		next = next->next;
+	}
+	*crnt = nullptr;
+}
+
+void stack::clear() {
+	node* next = head;
+	while ( next ) {
+		node* crnt = next;
+		next = crnt->next;
+		delete crnt;
+	}
+}
+
+stack::stack() : head(nullptr) {}
+
+stack::stack(const stack& o) { copy(o); }
+
+stack::stack(stack&& o) : head(o.head) { o.head = nullptr; }
+
+stack::~stack() { clear(); }
+
+stack& stack::operator= (const stack& o) {
+	if ( this == &o ) return *this;
+	clear();
+	copy(o);
+	return *this;
+}
+
+stack& stack::operator= (stack&& o) {
+	if ( this == &o ) return *this;
+	head = o.head;
+	o.head = nullptr;
+	return *this;
+}
+
+bool stack::empty() const {
+	return head == nullptr;
+}
+
+void stack::push(std::unique_ptr<object>&& value) {
+	head = new node{ std::move(value), head };
+}
+
+std::unique_ptr<object> stack::pop() {
+	node* n = head;
+	head = n->next;
+	std::unique_ptr<object> x = std::move(n->value);
+	delete n;
+	return x;
+}
Index: doc/generic_types/evaluation/cpp-vstack.hpp
===================================================================
--- doc/generic_types/evaluation/cpp-vstack.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/cpp-vstack.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "object.hpp"
+
+class stack {
+	struct node {
+		std::unique_ptr<object> value;
+		node* next;
+
+		node( const object& v );
+
+		node( std::unique_ptr<object>&& v, node* n );
+	};
+
+	node* head;
+
+	void copy(const stack& o);
+
+public:
+	void clear();
+
+	stack();
+
+	stack(const stack& o);
+
+	stack(stack&& o);
+
+	~stack();
+
+	stack& operator= (const stack& o);
+	
+	stack& operator= (stack&& o);
+
+	bool empty() const;
+
+	void push(std::unique_ptr<object>&& value);
+
+	std::unique_ptr<object> pop();
+};
Index: doc/generic_types/evaluation/object.hpp
===================================================================
--- doc/generic_types/evaluation/object.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
+++ doc/generic_types/evaluation/object.hpp	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <exception>
+#include <memory>
+#include <string>
+#include <typeinfo>
+#include <typeindex>
+
+class bad_cast : public std::exception {
+	std::string why;
+public:
+	bad_cast( const std::type_index& f, const std::type_index& t ) : std::exception() {
+		why = std::string{"bad cast of "} + f.name() + " to " + t.name();
+	}
+
+	~bad_cast() override = default;
+	
+	const char* what() const noexcept override { return why.c_str(); }
+};
+
+class object {
+public:
+	std::type_index get_class() const { return { typeid(*this) }; }
+
+	template<typename T>
+	T& as() {
+		std::type_index from = get_class(), to = { typeid(T) };
+		if ( from != to ) throw bad_cast{ from, to };
+		return reinterpret_cast<T&>(*this);
+	}
+
+	template<typename T>
+	const T& as() const {
+		std::type_index from = get_class(), to = { typeid(T) };
+		if ( from != to ) throw bad_cast{ from, to };
+		return reinterpret_cast<const T&>(*this);
+	}
+
+	virtual std::unique_ptr<object> new_inst() const = 0;
+	
+	virtual std::unique_ptr<object> new_copy() const = 0;
+	
+	virtual object& operator= (const object&) = 0;
+	
+	virtual ~object() = default;
+};
+
+class integer : public object {
+private:
+	int x;
+
+public:
+	integer() = default;
+
+	integer(int x) : x(x) {}
+
+	std::unique_ptr<object> new_inst() const override { return std::make_unique<integer>(); }
+	
+	std::unique_ptr<object> new_copy() const override { return std::make_unique<integer>(*this); }
+
+	integer& operator= (const integer& that) {
+		x = that.x;
+		return *this;	
+	}
+
+	object& operator= (const object& that) override {
+		std::type_index from = that.get_class(), to = get_class();
+		if ( from != to ) throw bad_cast{ from, to };
+		return *this = reinterpret_cast<const integer&>(that);
+	}
+
+	~integer() override = default;
+
+	integer& operator+= (const integer& that) {
+		x += that.x;
+		return *this;
+	}
+};
Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision b0fedd4a9c5fd3d6488160b3fd9bb16e03e6b651)
+++ src/GenPoly/Box.cc	(revision 7a054e82ffc088e8a736a51ccd98a191cc053ddf)
@@ -34,4 +34,5 @@
 #include "Parser/ParseNode.h"
 
+#include "SynTree/Attribute.h"
 #include "SynTree/Constant.h"
 #include "SynTree/Declaration.h"
@@ -165,4 +166,6 @@
 			using Parent::mutate;
 
+			PolyGenericCalculator();
+
 			template< typename DeclClass >
 			DeclClass *handleDecl( DeclClass *decl, Type *type );
@@ -198,4 +201,5 @@
 			ScopedSet< std::string > knownLayouts;          ///< Set of generic type layouts known in the current scope, indexed by sizeofName
 			ScopedSet< std::string > knownOffsets;          ///< Set of non-generic types for which the offset array exists in the current scope, indexed by offsetofName
+			UniqueName bufNamer;                           ///< Namer for VLA buffers
 		};
 
@@ -1452,4 +1456,7 @@
 ////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////////////////////////
 
+		PolyGenericCalculator::PolyGenericCalculator()
+			: Parent(), knownLayouts(), knownOffsets(), bufNamer( "_buf" ) {}
+
 		void PolyGenericCalculator::beginTypeScope( Type *ty ) {
 			scopeTyVars.beginScope();
@@ -1528,14 +1535,16 @@
 			if ( ObjectDecl *objectDecl = dynamic_cast< ObjectDecl *>( declStmt->get_decl() ) ) {
 				if ( findGeneric( objectDecl->get_type() ) ) {
-					// change initialization of a polymorphic value object
-					// to allocate storage with alloca
+					// change initialization of a polymorphic value object to allocate via a VLA
+					// (alloca was previously used, but can't be safely used in loops)
 					Type *declType = objectDecl->get_type();
-					UntypedExpr *alloc = new UntypedExpr( new NameExpr( "__builtin_alloca" ) );
-					alloc->get_args().push_back( new NameExpr( sizeofName( mangleType( declType ) ) ) );
+					std::string bufName = bufNamer.newName();
+					ObjectDecl *newBuf = new ObjectDecl( bufName, Type::StorageClasses(), LinkageSpec::C, 0, 
+						new ArrayType( Type::Qualifiers(), new BasicType( Type::Qualifiers(), BasicType::Kind::Char), new NameExpr( sizeofName( mangleType(declType) ) ), 
+						true, false, std::list<Attribute*>{ new Attribute( std::string{"aligned"}, std::list<Expression*>{ new ConstantExpr( Constant::from_int(8) ) } ) } ), 0 );
+					stmtsToAdd.push_back( new DeclStmt( noLabels, newBuf ) );
 
 					delete objectDecl->get_init();
 
-					std::list<Expression*> designators;
-					objectDecl->set_init( new SingleInit( alloc, designators, false ) ); // not constructed
+					objectDecl->set_init( new SingleInit( new NameExpr( bufName ) ) );
 				}
 			}
