Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Decl.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -26,5 +26,5 @@
 #include "ParseNode.hpp"
 #include "StorageClasses.hpp"
-#include "Type.hpp"            // for Type, ptr<Type>
+#include "TypeVar.hpp"
 #include "Visitor.hpp"
 #include "Parser/ParseNode.h"  // for DeclarationNode::Aggregate
@@ -136,6 +136,5 @@
 class TypeDecl final : public NamedTypeDecl {
 public:
-	/// type variable variants. otype is a specialized dtype
-	enum Kind { Dtype, Ftype, Ttype, NUMBER_OF_KINDS } kind;
+	TypeVar::Kind kind;
 	bool sized;
 	ptr<Type> init;
@@ -143,10 +142,10 @@
 	/// Data extracted from a type decl
 	struct Data {
-		Kind kind;
+		TypeVar::Kind kind;
 		bool isComplete;
 
-		Data() : kind( (Kind)-1 ), isComplete( false ) {}
+		Data() : kind( (TypeVar::Kind)-1 ), isComplete( false ) {}
 		Data( TypeDecl* d ) : kind( d->kind ), isComplete( d->sized ) {}
-		Data( Kind k, bool c ) : kind( k ), isComplete( c ) {}
+		Data( TypeVar::Kind k, bool c ) : kind( k ), isComplete( c ) {}
 		Data( const Data& d1, const Data& d2 )
 		: kind( d1.kind ), isComplete( d1.isComplete || d2.isComplete ) {}
@@ -159,10 +158,14 @@
 
 	TypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage, Type* b,
-		Kind k, bool s, Type* i = nullptr )
-	: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ), init( i ) {}
+		TypeVar::Kind k, bool s, Type* i = nullptr )
+	: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeVar::Ttype || s ), 
+	  init( i ) {}
 
 	std::string typeString() const override;
 	/// Produces a name for generated code
 	std::string genTypeString() const;
+
+	/// convenience accessor to match Type::isComplete()
+	bool isComplete() { return sized; }
 
 	Decl* accept( Visitor& v ) override { return v.visit( this ); }
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Expr.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -119,5 +119,5 @@
 	Expr(const CodeLocation & loc ) : ParseNode( loc ), result(), env(), inferred() {}
 
-	Expr* set_extension( bool ex ) { extension = ex; return this; }
+	Expr * set_extension( bool ex ) { extension = ex; return this; }
 
 	virtual Expr * accept( Visitor & v ) override = 0;
@@ -133,5 +133,5 @@
 	TypeExpr( const CodeLocation & loc, const Type * t ) : Expr(loc), type(t) {}
 
-	Expr* accept( Visitor & v ) override { return v.visit( this ); }
+	Expr * accept( Visitor & v ) override { return v.visit( this ); }
 private:
 	TypeExpr * clone() const override { return new TypeExpr{ *this }; }
Index: src/AST/FunctionSpec.hpp
===================================================================
--- src/AST/FunctionSpec.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/FunctionSpec.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -43,5 +43,5 @@
 		};
 
-		constexpr spec_flags( unsigned int val ) : val(val) {}
+		constexpr spec_flags( unsigned int val = 0 ) : val(val) {}
 	};
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Fwd.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -118,5 +118,4 @@
 class TupleType;
 class TypeofType;
-class AttrType;
 class VarArgsType;
 class ZeroType;
@@ -333,6 +332,4 @@
 inline void increment( const class TypeofType *, Node::ref_type );
 inline void decrement( const class TypeofType *, Node::ref_type );
-inline void increment( const class AttrType *, Node::ref_type );
-inline void decrement( const class AttrType *, Node::ref_type );
 inline void increment( const class VarArgsType *, Node::ref_type );
 inline void decrement( const class VarArgsType *, Node::ref_type );
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Init.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -42,10 +42,13 @@
 };
 
+/// Flag for whether to construct from initialzier
+enum ConstructFlag { DoConstruct, MaybeConstruct };
+
 /// Object initializer base class
 class Init : public ParseNode {
 public:
-	bool maybeConstructed;
+	ConstructFlag maybeConstructed;
 
-	Init( const CodeLocation& loc, bool mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
+	Init( const CodeLocation& loc, ConstructFlag mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
 
 	virtual Init* accept( Visitor& v ) override = 0;
@@ -60,5 +63,5 @@
 	ptr<Expr> value;
 
-	SingleInit( const CodeLocation& loc, Expr* val, bool mc = false )
+	SingleInit( const CodeLocation& loc, Expr* val, ConstructFlag mc = DoConstruct )
 	: Init( loc, mc ), value( val ) {}
 
@@ -78,5 +81,5 @@
 
 	ListInit( const CodeLocation& loc, std::vector<ptr<Init>>&& is,
-		std::vector<ptr<Designation>>&& ds = {}, bool mc = false );
+		std::vector<ptr<Designation>>&& ds = {}, ConstructFlag mc = DoConstruct );
 
 	using iterator = std::vector<ptr<Init>>::iterator;
@@ -104,5 +107,5 @@
 
 	ConstructorInit( const CodeLocation& loc, Stmt* ctor, Stmt* dtor, Init* init )
-	: Init( loc, true ), ctor( ctor ), dtor( dtor ), init( init ) {}
+	: Init( loc, DoConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
 
 	Init* accept( Visitor& v ) override { return v.visit( this ); }
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Node.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -94,25 +94,24 @@
 std::ostream& operator<< ( std::ostream& out, const Node* node );
 
-// Base class for the smart pointer types
-// should never really be used.
-template< typename node_t, enum Node::ref_type ref_t>
+/// Base class for the smart pointer types
+/// should never really be used.
+template< typename node_t, enum Node::ref_type ref_t >
 class ptr_base {
 public:
 	ptr_base() : node(nullptr) {}
-	ptr_base( node_t * n ) : node(n) { if( !node ) node->increment(ref_t); }
+	ptr_base( const node_t * n ) : node(n) { if( node ) node->increment(ref_t); }
 	~ptr_base() { if( node ) node->decrement(ref_t); }
 
-	template< enum  Node::ref_type o_ref_t >
+	template< enum Node::ref_type o_ref_t >
 	ptr_base( const ptr_base<node_t, o_ref_t> & o ) : node(o.node) {
-		if( !node ) return;
-		node->increment(ref_t);
+		if( node ) node->increment(ref_t);
 	}
 
-	template< enum  Node::ref_type o_ref_t >
+	template< enum Node::ref_type o_ref_t >
 	ptr_base( ptr_base<node_t, o_ref_t> && o ) : node(o.node) {
 		if( node ) node->increment(ref_t);
 	}
 
-	template< enum  Node::ref_type o_ref_t >
+	template< enum Node::ref_type o_ref_t >
 	ptr_base & operator=( const ptr_base<node_t, o_ref_t> & o ) {
 		assign(o.node);
@@ -120,7 +119,6 @@
 	}
 
-	template< enum  Node::ref_type o_ref_t >
+	template< enum Node::ref_type o_ref_t >
 	ptr_base & operator=( ptr_base<node_t, o_ref_t> && o ) {
-		if(o.node == node) return *this;
 		assign(o.node);
 		return *this;
@@ -134,10 +132,10 @@
 
 	template<typename o_node_t>
-	const o_node_t * as() const { return dynamic_cast<o_node_t *>(node); }
+	const o_node_t * as() const { return dynamic_cast<const o_node_t *>(node); }
 
 	using ptr = const node_t *;
 
 private:
-	void assign(node_t * other ) {
+	void assign( const node_t * other ) {
 		if( other ) other->increment(ref_t);
 		if( node  ) node ->decrement(ref_t);
@@ -146,5 +144,5 @@
 
 protected:
-	node_t * node;
+	const node_t * node;
 };
 
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Pass.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -161,5 +161,4 @@
 	virtual Type *             visit( const TupleType            * ) override final;
 	virtual Type *             visit( const TypeofType           * ) override final;
-	virtual Type *             visit( const AttrType             * ) override final;
 	virtual Type *             visit( const VarArgsType          * ) override final;
 	virtual Type *             visit( const ZeroType             * ) override final;
Index: src/AST/StorageClasses.hpp
===================================================================
--- src/AST/StorageClasses.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/StorageClasses.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -47,5 +47,5 @@
 		};
 
-		constexpr class_flags( unsigned int val ) : val(val) {}
+		constexpr class_flags( unsigned int val = 0 ) : val(val) {}
 	};
 
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Type.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -16,17 +16,489 @@
 #pragma once
 
-#include "Node.hpp"
+#include <cassert>
+#include <cstddef>           // for nullptr_t
+#include <cstdint>           // for uintptr_t
+#include <utility>           // for move
+#include <vector>
+
+#include "CVQualifiers.hpp"
+#include "Fwd.hpp"
+#include "Node.hpp"          // for Node, ptr
+#include "TypeVar.hpp"
+#include "Visitor.hpp"
 
 namespace ast {
 
 class Type : public Node {
-
-};
-
-
+	CV::Qualifiers tq;
+public:
+	Type( CV::Qualifiers q = {} ) : tq(q) {}
+
+	CV::Qualifiers qualifiers() const { return tq; }
+	bool is_const() const { return tq.is_const; }
+	bool is_volatile() const { return tq.is_volatile; }
+	bool is_restrict() const { return tq.is_restrict; }
+	bool is_lvalue() const { return tq.is_lvalue; }
+	bool is_mutex() const { return tq.is_mutex; }
+	bool is_atomic() const { return tq.is_atomic; }
+
+	void set_qualifiers( CV::Qualifiers q ) { tq = q; }
+	void set_const( bool v ) { tq.is_const = v; }
+	void set_restrict( bool v ) { tq.is_restrict = v; }
+	void set_lvalue( bool v ) { tq.is_lvalue = v; }
+	void set_mutex( bool v ) { tq.is_mutex = v; }
+	void set_atomic( bool v ) { tq.is_atomic = v; }
+
+	/// How many elemental types are represented by this type
+	virtual unsigned size() const { return 1; }
+	/// Is this a void type?
+	virtual bool isVoid() const { return size() == 0; }
+	/// Get the i'th component of this type
+	virtual const Type * getComponent( unsigned i );
+
+	/// type without outer pointers and arrays
+	const Type * stripDeclarator();
+	/// type without outer references
+	const Type * stripReferences();
+	/// number of reference occuring consecutively on the outermost layer of this type
+	/// (i.e. do not count references nested within other types)
+	virtual unsigned referenceDepth() const { return 0; }
+	/// true iff type is complete type (i.e. compiler knows the size, alignment, and layout)
+	virtual bool isComplete() const { return true; }
+
+	virtual Type * accept( Visitor & v ) override = 0;
+private:
+	virtual Type * clone() const override = 0;
+};
+
+/// `void`
+class VoidType final : public Type {
+public:
+	VoidType( CV::Qualifiers q = {} ) : Type( q ) {}
+	
+	unsigned size() const override { return 0; }
+	bool isVoid() const override { return true; }
+	bool isComplete() const override { return false; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	VoidType * clone() const override { return new VoidType{ *this }; }
+};
+
+/// Built-in arithmetic type
+class BasicType final : public Type {
+public:
+	// GENERATED START, DO NOT EDIT
+	// GENERATED BY BasicTypes-gen.cc
+	enum Kind {
+		Bool,
+		Char,
+		SignedChar,
+		UnsignedChar,
+		ShortSignedInt,
+		ShortUnsignedInt,
+		SignedInt,
+		UnsignedInt,
+		LongSignedInt,
+		LongUnsignedInt,
+		LongLongSignedInt,
+		LongLongUnsignedInt,
+		SignedInt128,
+		UnsignedInt128,
+		uFloat16,
+		uFloat16Complex,
+		uFloat32,
+		uFloat32Complex,
+		Float,
+		FloatComplex,
+		uFloat32x,
+		uFloat32xComplex,
+		uFloat64,
+		uFloat64Complex,
+		Double,
+		DoubleComplex,
+		uFloat64x,
+		uFloat64xComplex,
+		uuFloat80,
+		uFloat128,
+		uFloat128Complex,
+		uuFloat128,
+		LongDouble,
+		LongDoubleComplex,
+		uFloat128x,
+		uFloat128xComplex,
+		NUMBER_OF_BASIC_TYPES
+	} kind;
+	// GENERATED END
+
+	/// xxx -- MAX_INTEGER_TYPE should probably be in BasicTypes-gen.cc, rather than hardcoded here
+	enum { MAX_INTEGER_TYPE = UnsignedInt128 };
+
+	/// string names of basic types; generated to match with Kind
+	static const char *typeNames[];
+
+	BasicType( Kind k, CV::Qualifiers q = {} ) : Type(q), kind(k) {}
+
+	/// Check if this type represents an integer type
+	bool isInteger() const { return kind <= MAX_INTEGER_TYPE; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	BasicType * clone() const override { return new BasicType{ *this }; }
+};
+
+/// Pointer/array variable length?
+enum LengthFlag { FixedLen, VariableLen };
+
+/// Pointer/array static dimension?
+enum DimensionFlag { DynamicDim, StaticDim };
+
+/// Pointer type `T*`
+class PointerType final : public Type {
+public:
+	ptr<Type> base;
+
+	// In C99, pointer types can be qualified in many ways, e.g. `int a[ static 3 ]`
+	ptr<Expr> dimension;
+	LengthFlag isVarLen = FixedLen;
+	DimensionFlag isStatic = DynamicDim;
+
+	PointerType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b), dimension() {}
+	PointerType( const Type * b, const Expr * d, LengthFlag vl, DimensionFlag s, 
+		CV::Qualifiers q = {} ) : Type(q), base(b), dimension(d), isVarLen(vl), isStatic(s) {}
+
+	// true if this pointer is actually an array
+	bool isArray() const { return isVarLen || isStatic || dimension; }
+
+	bool isComplete() const override { return ! isVarLen; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	PointerType * clone() const override { return new PointerType{ *this }; }
+};
+
+/// Array type `T[]`
+class ArrayType final : public Type {
+public:
+	ptr<Type> base;
+	ptr<Expr> dimension;
+	LengthFlag isVarLen;
+	DimensionFlag isStatic;
+
+	ArrayType( const Type * b, const Expr * d, LengthFlag vl, DimensionFlag s, 
+		CV::Qualifiers q = {} ) : Type(q), base(b), dimension(d), isVarLen(vl), isStatic(s) {}
+
+	// array types are complete if they have a dimension expression or are
+	// VLAs ('*' in parameter declaration), and incomplete otherwise.
+	// See 6.7.6.2
+	bool isComplete() const override { return dimension || isVarLen; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	ArrayType * clone() const override { return new ArrayType{ *this }; }
+};
+
+/// Reference type `T&`
+class ReferenceType final : public Type {
+public:
+	ptr<Type> base;
+
+	ReferenceType( const Type * b, CV::Qualifiers q = {} ) : Type(q), base(b) {}
+
+	unsigned referenceDepth() const override { return base->referenceDepth() + 1; }
+
+	// Since reference types act like value types, their size is the size of the base.
+	// This makes it simple to cast the empty tuple to a reference type, since casts that increase
+	// the number of values are disallowed.
+	unsigned size() const override { return base->size(); }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	ReferenceType * clone() const override { return new ReferenceType{ *this }; }
+};
+
+/// Qualified type `P.C`
+class QualifiedType final : public Type {
+public:
+	ptr<Type> parent;
+	ptr<Type> child;
+
+	QualifiedType( const Type * p, const Type * c, CV::Qualifiers q = {} ) 
+	: Type(q), parent(p), child(c) {}
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	QualifiedType * clone() const override { return new QualifiedType{ *this }; }
+};
+
+/// Base type for potentially forall-qualified types
+class ParameterizedType : public Type {
+public:
+	using ForallList = std::vector<ptr<TypeDecl>>;
+
+	ForallList forall;
+
+	ParameterizedType( ForallList&& fs = {}, CV::Qualifiers q = {} ) 
+	: Type(q), forall(std::move(fs)) {}
+	ParameterizedType( CV::Qualifiers q ) : Type(q), forall() {}
+
+private:
+	virtual ParameterizedType * clone() const override = 0;
+};
+
+/// Function variable arguments flag
+enum ArgumentFlag { FixedArgs, VariableArgs };
+
+/// Type of a function `[R1, R2](*)(P1, P2, P3)`
+class FunctionType final : public ParameterizedType {
+public:
+	std::vector<ptr<DeclWithType>> returnVals;
+	std::vector<ptr<DeclWithType>> parameters;
+
+	/// Does the function accept a variable number of arguments following the arguments specified 
+	/// in the parameters list.
+	/// This could be because of
+	/// - an ellipsis in a prototype declaration
+	/// - an unprototyped declaration
+	ArgumentFlag isVarArgs;
+
+	FunctionType( ArgumentFlag va = FixedArgs, CV::Qualifiers q = {} )
+	: ParameterizedType(q), returnVals(), parameters(), isVarArgs(va) {}
+
+	/// true if either the parameters or return values contain a tttype
+	bool isTtype() const;
+	/// true if function parameters are unconstrained by prototype
+	bool isUnprototyped() const { return isVarArgs && parameters.size() == 0; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	FunctionType * clone() const override { return new FunctionType{ *this }; }
+};
+
+/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
+class ReferenceToType : public ParameterizedType {
+public:
+	std::vector<ptr<Expr>> parameters;
+	std::vector<ptr<Attribute>> attributes;
+	std::string name;
+	bool hoistType = false;
+
+	ReferenceToType( const std::string& n, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ParameterizedType(q), parameters(), attributes(std::move(as)), name(n) {}
+
+	/// Gets aggregate declaration this type refers to
+	virtual const AggregateDecl * aggr() const = 0;
+	/// Looks up member declarations with given name
+	std::vector<readonly<Decl>> lookup( const std::string & name ) const;
+
+private:
+	virtual ReferenceToType * clone() const override = 0;
+
+protected:
+	/// Name for the kind of type this is
+	virtual std::string typeString() const = 0;
+};
+
+/// instance of struct type
+class StructInstType final : public ReferenceToType {
+public:
+	readonly<StructDecl> base;
+
+	StructInstType( const std::string& n, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base() {}
+	StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} );
+	
+	bool isComplete() const override;
+
+	const StructDecl * aggr() const override { return base; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	StructInstType * clone() const override { return new StructInstType{ *this }; }
+
+	std::string typeString() const override { return "struct"; }
+};
+
+/// instance of union type
+class UnionInstType final : public ReferenceToType {
+public:
+	readonly<UnionDecl> base;
+
+	UnionInstType( const std::string& n, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base() {}
+	UnionInstType( const UnionDecl * b, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} );
+	
+	bool isComplete() const override;
+
+	const UnionDecl * aggr() const override { return base; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	UnionInstType * clone() const override { return new UnionInstType{ *this }; }
+
+	std::string typeString() const override { return "union"; }
+};
+
+/// instance of enum type
+class EnumInstType final : public ReferenceToType {
+public:
+	readonly<EnumDecl> base;
+
+	EnumInstType( const std::string& n, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base() {}
+	EnumInstType( const EnumDecl * b, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} );
+	
+	bool isComplete() const override;
+
+	const EnumDecl * aggr() const override { return base; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	EnumInstType * clone() const override { return new EnumInstType{ *this }; }
+
+	std::string typeString() const override { return "enum"; }
+};
+
+/// instance of trait type
+class TraitInstType final : public ReferenceToType {
+public:
+	readonly<TraitDecl> base;
+
+	TraitInstType( const std::string& n, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base() {}
+	TraitInstType( const TraitDecl * b, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} );
+	
+	// not meaningful for TraitInstType
+	bool isComplete() const override { assert(false); }
+
+	const TraitDecl * aggr() const override { return base; }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	TraitInstType * clone() const override { return new TraitInstType{ *this }; }
+
+	std::string typeString() const override { return "trait"; }
+};
+
+/// instance of named type alias (typedef or variable)
+class TypeInstType final : public ReferenceToType {
+public:
+	readonly<TypeDecl> base;
+	TypeVar::Kind kind;
+
+	TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
+	TypeInstType( const std::string& n, TypeVar::Kind k, CV::Qualifiers q = {}, 
+		std::vector<ptr<Attribute>> && as = {} )
+	: ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
+
+	/// sets `base`, updating `kind` correctly
+	void set_base( const TypeDecl * );
+
+	bool isComplete() const override;
+
+	// not meaningful for TypeInstType
+	const AggregateDecl * aggr() const override { assert(false); }
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	TypeInstType * clone() const override { return new TypeInstType{ *this }; }
+
+	std::string typeString() const override { return "type"; }
+};
+
+/// tuple type e.g. `[int, char]`
+class TupleType final : public Type {
+public:
+	std::vector<ptr<Type>> types;
+	std::vector<ptr<Decl>> members;
+
+	TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
+
+	// collection simulation
+	using iterator = std::vector<ptr<Type>>::const_iterator;
+	iterator begin() const { return types.begin(); }
+	iterator end() const { return types.end(); }
+	
+	unsigned size() const override { return types.size(); }
+
+	const Type * getComponent( unsigned i ) override {
+		assertf( i < size(), "TupleType::getComponent: index %d must be less than size %d", 
+			i, size() );
+		return *(begin()+i);
+	}
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	TupleType * clone() const override { return new TupleType{ *this }; }
+};
+
+/// Type of unresolved `typeof()` expression
+class TypeofType : public Type {
+public:
+	ptr<Expr> expr;
+	enum Kind { Typeof, Basetypeof } kind;
+
+	TypeofType( const Expr * e, Kind k = Typeof, CV::Qualifiers q = {} ) 
+	: Type(q), expr(e), kind(k) {}
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	TypeofType * clone() const override { return new TypeofType{ *this }; }
+};
+
+/// GCC built-in varargs type
+class VarArgsType final : public Type {
+public:
+	VarArgsType( CV::Qualifiers q = {} ) : Type( q ) {}
+	
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	VarArgsType * clone() const override { return new VarArgsType{ *this }; }
+};
+
+/// Type of zero constant `0`
+class ZeroType final : public Type {
+public:
+	ZeroType( CV::Qualifiers q = {} ) : Type( q ) {}
+	
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	ZeroType * clone() const override { return new ZeroType{ *this }; }	
+};
+
+/// Type of one constant `1`
+class OneType final : public Type {
+public:
+	OneType( CV::Qualifiers q = {} ) : Type( q ) {}
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	OneType * clone() const override { return new OneType{ *this }; }
+};
+
+/// Parent type for scope-qualified types at global scope
+class GlobalScopeType final : public Type {
+public:
+	GlobalScopeType( CV::Qualifiers q = {} ) : Type( q ) {}
+
+	Type * accept( Visitor & v ) override { return v.visit( this ); }
+private:
+	GlobalScopeType * clone() const override { return new GlobalScopeType{ *this }; }
+};
 
 //=================================================================================================
 /// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
-/// remove only if there is a better solution
+/// remove only if there is a better solution.
 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
 /// forward declarations
@@ -63,6 +535,4 @@
 inline void increment( const class TypeofType * node, Node::ref_type ref ) { node->increment( ref ); }
 inline void decrement( const class TypeofType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class AttrType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class AttrType * node, Node::ref_type ref ) { node->decrement( ref ); }
 inline void increment( const class VarArgsType * node, Node::ref_type ref ) { node->increment( ref ); }
 inline void decrement( const class VarArgsType * node, Node::ref_type ref ) { node->decrement( ref ); }
Index: src/AST/TypeVar.hpp
===================================================================
--- src/AST/TypeVar.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
+++ src/AST/TypeVar.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -0,0 +1,34 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// TypeVar.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed May 15 15:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Wed May 15 15:00:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+namespace ast {
+
+namespace TypeVar {
+
+/// type variable variants.
+/// `otype` is treated as a constrainted `dtype`
+enum Kind { Dtype, Ftype, Ttype, NUMBER_OF_KINDS };
+
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/Visitor.hpp	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -104,5 +104,4 @@
     virtual Type *             visit( const TupleType            * ) = 0;
     virtual Type *             visit( const TypeofType           * ) = 0;
-    virtual Type *             visit( const AttrType             * ) = 0;
     virtual Type *             visit( const VarArgsType          * ) = 0;
     virtual Type *             visit( const ZeroType             * ) = 0;
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 264e69123587f0b13a2568bfb5159dd8fbdabf6b)
+++ src/AST/porting.md	(revision 9e1d48503286c2f21bf3f599590920efc8b02293)
@@ -32,5 +32,5 @@
 * allows compiler to optimize virtual calls to static calls if given static type
 
-Pulled `FuncSpecifiers` and `StorageClasses` out of `Type` into their own headers
+Pulled `FuncSpecifiers`, `StorageClasses`, `CVQualifiers` out of `Type` into their own headers
 * Made `BFCommon` a `MakeBitfield` macro in its own header
   * added default and field-init constructors to macro
@@ -66,7 +66,13 @@
 	* `Initializer` => `ast::Init`
     * `Statement` => `ast::Stmt`
+	* any field names should follow a similar renaming
   * because they don't really belong to `Type` (and for consistency with `Linkage::Spec`):
     * `Type::StorageClasses` => `ast::Storage::Classes`
 	  * `Type::Extern` etc. => `ast::Storage::Extern` etc.
+	* `Type::FuncSpecifiers` => `ast::Function::Specs`
+	  * `Type::Inline` etc. => `ast::Function::Inline` etc.
+	* `Type::Qualifiers` => `ast::CV::Qualifiers`
+	  * `Type::Const` etc. => `ast::CV::Const`
+	  * couldn't break name-dependency loop without pulling `Qualifiers` out of `Type`
 	* `LinkageSpec::Spec` => `ast::Linkage::Spec`
 	  * `LinkageSpec::Mangle` etc. => `ast::Linkage::Mangle` etc.
@@ -75,4 +81,8 @@
 	  * `LinkageSpec::isMangled(Spec)` etc. => `Spec.is_mangled` etc.
 	  * `LinkageSpec::Intrinsic` etc. => `ast::Linkage::Intrinsic` etc.
+* Boolean constructor parameters get replaced with a dedicated flag enum:
+  * e.g. `bool isVarLen;` => `enum LengthFlag { FixedLen, VariableLen };` `LengthFlag isVarLen;`
+  * field can be *read* in the existing boolean contexts, but requires documentation to write
+  * suggest naming all flag enums `FooFlag` to hint at boolean nature
 
 ## Specific Nodes ##
@@ -93,5 +103,5 @@
 
 `TypeDecl`
-* stripped `isComplete()` accessor in favour of direct access to `sized`
+* moved `TypeDecl::Kind` to `ast::TypeVar::Kind`
 
 `EnumDecl`
@@ -102,4 +112,7 @@
   * does imply get_/set_ API, and some care about moving backward
 
+`Init`
+* `bool maybeConstruct` => `enum ConstructFlag { DoConstruct, MaybeConstruct }`
+
 `Label`
 * `get_statement()` exclusively used for code location, replaced with `CodeLocation` field
@@ -108,23 +121,55 @@
 * **TODO** port copy operator
   * Needs to be an almost-shallow clone, where the declarations are cloned only if needed
-  * **TODO** port DeclReplacer
+  * **TODO** port `DeclReplacer`
 * Still a `std::list` for children, rather than `std::vector`
   * allows more-efficient splicing for purposes of later code generation
 
 `Type`
+* `CV::Qualifiers` moved to end of constructor parameter list, defaulted to `{}`
+  * `ReferenceToType` puts a defaulted list of attributes after qualifiers
 * `forall` field split off into `ParameterizedType` subclass
   * any type that needs it can inherit from `ParameterizedType`
+    * currently `FunctionType`, `ReferenceToType`
 * `get_qualifiers()` replaced with accessor `qualifiers()` and mutator `set_qualifiers()`
-  * `get_CV()` replaced with `is_CV()` variants
+  * `get_const()` etc. replaced with `is_const()` etc. variants
+* `referenceDepth()` now returns `unsigned` rather than `int`
 * A number of features only supported on aggregates pushed down to `ReferenceToType`:
   * `attributes`: per docs [1] GCC only supports type attributes on aggregates and typedefs
     * suggest adding a `TypeWithAttributes` wrapper type if this proves insufficient
-  * `getAggr()`
-  * `genericSubstitution()`
+  * `getAggr()` => `aggr()`
+    * also now returns `const AggregateDecl *`
+* `genericSubstitution()` moved to own visitor **TODO** write
 
 `BasicType`
-* does not inherit from `Type` to allow pointer inlining
-* moved `Kind` before qualifiers in constructor to allow for default
 * **TODO** move `kind`, `typeNames` into code generator
+
+`ReferenceToType`
+* deleted `get_baseParameters()` from children
+  * replace with `aggr() ? aggr()->parameters : nullptr`
+* hoisted `lookup` implementation into parent, made non-virtual
+  * also changed to return vector rather than filling; change back if any great win for reuse
+* `baseStruct` etc. renamed to `base`
+
+`PointerType`/`ArrayType`
+* `is_array()` => `isArray()`
+* `bool isVarLen;` => `enum LengthFlag { FixedLen, VariableLen }; LengthFlag isVarLen;`
+* `bool isStatic;` => `enum DimensionFlag { DynamicDim, StaticDim }; DimensionFlag isStatic;`
+
+`FunctionType`
+* `bool isVarArgs;` => `enum ArgumentFlag { FixedArgs, VariableArgs }; ArgumentFlag isVarArgs;`
+
+`TypeInstType`
+* `bool isFtype` => `TypeVar::Kind kind`
+
+`TypeofType`
+* `bool is_basetypeof` => `enum Kind { Typeof, Basetypeof } kind;`
+
+`TupleType`
+* removed `value_type` typedef due to likely error
+  * if readded, should be `const Type *`
+
+`AttrType`
+* did not port due to (likely) disuse
+  * best guess at use (from printing code) is deprecated handling for attributes
 
 [1] https://gcc.gnu.org/onlinedocs/gcc-9.1.0/gcc/Type-Attributes.html#Type-Attributes
