Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Decl.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -57,7 +57,7 @@
 	static readonly<Decl> fromId( UniqueId id );
 
-	virtual const Decl * accept( Visitor & v ) const override = 0;
-private:
-	virtual Decl * clone() const override = 0;
+	const Decl * accept( Visitor & v ) const override = 0;
+private:
+	Decl * clone() const override = 0;
 };
 
@@ -87,9 +87,9 @@
 	virtual const Type * get_type() const = 0;
 	/// Set type of this declaration. May be verified by subclass
-	virtual void set_type(Type*) = 0;
-
-	virtual const DeclWithType * accept( Visitor & v ) const override = 0;
-private:
-	virtual DeclWithType * clone() const override = 0;
+	virtual void set_type(Type *) = 0;
+
+	const DeclWithType * accept( Visitor & v ) const override = 0;
+private:
+	DeclWithType * clone() const override = 0;
 };
 
@@ -108,9 +108,35 @@
 
 	const Type* get_type() const override { return type; }
-	void set_type( Type* ty ) override { type = ty; }
-
-	virtual const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	virtual ObjectDecl * clone() const override { return new ObjectDecl{ *this }; }
+	void set_type( Type * ty ) override { type = ty; }
+
+	const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
+private:
+	ObjectDecl * clone() const override { return new ObjectDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
+};
+
+class FunctionDecl : public DeclWithType {
+public:
+	ptr<FunctionType> type;
+	ptr<CompoundStmt> stmts;
+	std::list< ptr<Expr> > withExprs;
+
+	FunctionDecl( const CodeLocation & loc, const std::string &name, FunctionType * type,
+		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
+		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {})
+	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
+	  stmts( stmts ) {}
+
+	const Type * get_type() const override { return type.get(); }
+	void set_type(Type * t) override { type = strict_dynamic_cast< FunctionType* >( t ); }
+
+	bool has_body() const { return stmts; }
+
+	const DeclWithType * accept( Visitor &v ) const override { return v.visit( this ); }
+private:
+	FunctionDecl * clone() const override { return new FunctionDecl( *this ); }
 
 	/// Must be copied in ALL derived classes
@@ -170,7 +196,11 @@
 	std::string genTypeString() const;
 
-	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	virtual TypeDecl * clone() const override { return new TypeDecl{ *this }; }
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TypeDecl * clone() const override { return new TypeDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
@@ -184,7 +214,11 @@
 	std::string typeString() const override { return "typedef"; }
 
-	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	virtual TypedefDecl * clone() const override { return new TypedefDecl{ *this }; }
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TypedefDecl * clone() const override { return new TypedefDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
@@ -224,7 +258,11 @@
 	bool is_thread() { return kind == DeclarationNode::Thread; }
 
-	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	virtual StructDecl * clone() const override { return new StructDecl{ *this }; }
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	StructDecl * clone() const override { return new StructDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 
 	std::string typeString() const override { return "struct"; }
@@ -238,7 +276,11 @@
 	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
 
-	virtual const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
-private:
-	virtual UnionDecl * clone() const override { return new UnionDecl{ *this }; }
+	const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
+private:
+	UnionDecl * clone() const override { return new UnionDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 
 	std::string typeString() const override { return "union"; }
@@ -255,7 +297,11 @@
 	bool valueOf( Decl* enumerator, long long& value ) const;
 
-	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	virtual EnumDecl * clone() const override { return new EnumDecl{ *this }; }
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	EnumDecl * clone() const override { return new EnumDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 
 	std::string typeString() const override { return "enum"; }
@@ -272,11 +318,47 @@
 	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
 
-	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	virtual TraitDecl * clone() const override { return new TraitDecl{ *this }; }
+	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	TraitDecl * clone() const override { return new TraitDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 
 	std::string typeString() const override { return "trait"; }
 };
 
+class AsmDecl : public Decl {
+public:
+	ptr<AsmStmt> stmt;
+
+	AsmDecl( const CodeLocation & loc, AsmStmt *stmt )
+	: Decl( loc, "", {}, {} ), stmt(stmt) {}
+
+	const AsmDecl * accept( Visitor &v ) const override { return v.visit( this ); }
+private:
+	AsmDecl *clone() const override { return new AsmDecl( *this ); }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
+};
+
+class StaticAssertDecl : public Decl {
+public:
+	ptr<Expr> condition;
+	ptr<ConstantExpr> msg;   // string literal
+
+	StaticAssertDecl( const CodeLocation & loc, const Expr * condition, const ConstantExpr * msg )
+	: Decl( loc, "", {}, {} ), condition( condition ), msg( msg ) {}
+
+	const StaticAssertDecl * accept( Visitor &v ) const override { return v.visit( this ); }
+private:
+	StaticAssertDecl * clone() const override { return new StaticAssertDecl( *this ); }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
+};
 
 //=================================================================================================
@@ -291,6 +373,6 @@
 inline void increment( const class ObjectDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class ObjectDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 inline void increment( const class AggregateDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class AggregateDecl * node, Node::ref_type ref ) { node->decrement(ref); }
@@ -307,14 +389,10 @@
 inline void increment( const class TypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class TypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class FtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class FtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class DtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class DtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 inline void increment( const class TypedefDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class TypedefDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-// inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
-// inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 
 }
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Expr.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -121,7 +121,7 @@
 	Expr* set_extension( bool ex ) { extension = ex; return this; }
 
-	virtual const Expr * accept( Visitor& v ) const override = 0;
+	const Expr * accept( Visitor& v ) const override = 0;
 private:
-	virtual Expr * clone() const override = 0;
+	Expr * clone() const override = 0;
 };
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Fwd.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -33,6 +33,4 @@
 class NamedTypeDecl;
 class TypeDecl;
-class FtypeDecl;
-class DtypeDecl;
 class TypedefDecl;
 class AsmDecl;
@@ -171,8 +169,4 @@
 inline void increment( const class TypeDecl *, Node::ref_type );
 inline void decrement( const class TypeDecl *, Node::ref_type );
-inline void increment( const class FtypeDecl *, Node::ref_type );
-inline void decrement( const class FtypeDecl *, Node::ref_type );
-inline void increment( const class DtypeDecl *, Node::ref_type );
-inline void decrement( const class DtypeDecl *, Node::ref_type );
 inline void increment( const class TypedefDecl *, Node::ref_type );
 inline void decrement( const class TypedefDecl *, Node::ref_type );
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Init.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -37,7 +37,7 @@
 	: ParseNode( loc ), designators( std::move(ds) ) {}
 
-	virtual const Designation* accept( Visitor& v ) const override { return v.visit( this ); }
+	const Designation* accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	virtual Designation* clone() const override { return new Designation{ *this }; }
+	Designation* clone() const override { return new Designation{ *this }; }
 };
 
@@ -49,7 +49,7 @@
 	Init( const CodeLocation& loc, bool mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
 
-	virtual const Init * accept( Visitor& v ) const override = 0;
+	const Init * accept( Visitor& v ) const override = 0;
 private:
-	virtual const Init * clone() const override = 0;
+	const Init * clone() const override = 0;
 };
 
@@ -63,7 +63,7 @@
 	: Init( loc, mc ), value( val ) {}
 
-	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
+	const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	virtual SingleInit * clone() const override { return new SingleInit{ *this }; }
+	SingleInit * clone() const override { return new SingleInit{ *this }; }
 
 	/// Must be copied in ALL derived classes
@@ -91,7 +91,7 @@
 	const_iterator end() const { return initializers.end(); }
 
-	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
+	const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	virtual ListInit * clone() const override { return new ListInit{ *this }; }
+	ListInit * clone() const override { return new ListInit{ *this }; }
 
 	/// Must be copied in ALL derived classes
@@ -114,7 +114,7 @@
 	: Init( loc, true ), ctor( ctor ), dtor( dtor ), init( init ) {}
 
-	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
+	const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	virtual ConstructorInit * clone() const override { return new ConstructorInit{ *this }; }
+	ConstructorInit * clone() const override { return new ConstructorInit{ *this }; }
 
 	/// Must be copied in ALL derived classes
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Pass.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -85,98 +85,98 @@
 
 	/// Visit function declarations
-	virtual const ast::DeclWithType *     visit( const ast::ObjectDecl           * ) override final;
-	virtual const ast::DeclWithType *     visit( const ast::FunctionDecl         * ) override final;
-	virtual const ast::Decl *             visit( const ast::StructDecl           * ) override final;
-	virtual const ast::Decl *             visit( const ast::UnionDecl            * ) override final;
-	virtual const ast::Decl *             visit( const ast::EnumDecl             * ) override final;
-	virtual const ast::Decl *             visit( const ast::TraitDecl            * ) override final;
-	virtual const ast::Decl *             visit( const ast::TypeDecl             * ) override final;
-	virtual const ast::Decl *             visit( const ast::TypedefDecl          * ) override final;
-	virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * ) override final;
-	virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
-	virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
-	virtual const ast::Stmt *             visit( const ast::ExprStmt             * ) override final;
-	virtual const ast::Stmt *             visit( const ast::AsmStmt              * ) override final;
-	virtual const ast::Stmt *             visit( const ast::DirectiveStmt        * ) override final;
-	virtual const ast::Stmt *             visit( const ast::IfStmt               * ) override final;
-	virtual const ast::Stmt *             visit( const ast::WhileStmt            * ) override final;
-	virtual const ast::Stmt *             visit( const ast::ForStmt              * ) override final;
-	virtual const ast::Stmt *             visit( const ast::SwitchStmt           * ) override final;
-	virtual const ast::Stmt *             visit( const ast::CaseStmt             * ) override final;
-	virtual const ast::Stmt *             visit( const ast::BranchStmt           * ) override final;
-	virtual const ast::Stmt *             visit( const ast::ReturnStmt           * ) override final;
-	virtual const ast::Stmt *             visit( const ast::ThrowStmt            * ) override final;
-	virtual const ast::Stmt *             visit( const ast::TryStmt              * ) override final;
-	virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
-	virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
-	virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
-	virtual const ast::Stmt *             visit( const ast::WithStmt             * ) override final;
-	virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
-	virtual const ast::Stmt *             visit( const ast::DeclStmt             * ) override final;
-	virtual const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) override final;
-	virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
-	virtual const ast::Expr *             visit( const ast::NameExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::AddressExpr          * ) override final;
-	virtual const ast::Expr *             visit( const ast::LabelAddressExpr     * ) override final;
-	virtual const ast::Expr *             visit( const ast::CastExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::KeywordCastExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::VirtualCastExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::UntypedMemberExpr    * ) override final;
-	virtual const ast::Expr *             visit( const ast::MemberExpr           * ) override final;
-	virtual const ast::Expr *             visit( const ast::VariableExpr         * ) override final;
-	virtual const ast::Expr *             visit( const ast::ConstantExpr         * ) override final;
-	virtual const ast::Expr *             visit( const ast::SizeofExpr           * ) override final;
-	virtual const ast::Expr *             visit( const ast::AlignofExpr          * ) override final;
-	virtual const ast::Expr *             visit( const ast::UntypedOffsetofExpr  * ) override final;
-	virtual const ast::Expr *             visit( const ast::OffsetofExpr         * ) override final;
-	virtual const ast::Expr *             visit( const ast::OffsetPackExpr       * ) override final;
-	virtual const ast::Expr *             visit( const ast::AttrExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::LogicalExpr          * ) override final;
-	virtual const ast::Expr *             visit( const ast::ConditionalExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::CommaExpr            * ) override final;
-	virtual const ast::Expr *             visit( const ast::TypeExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::AsmExpr              * ) override final;
-	virtual const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) override final;
-	virtual const ast::Expr *             visit( const ast::ConstructorExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::CompoundLiteralExpr  * ) override final;
-	virtual const ast::Expr *             visit( const ast::RangeExpr            * ) override final;
-	virtual const ast::Expr *             visit( const ast::UntypedTupleExpr     * ) override final;
-	virtual const ast::Expr *             visit( const ast::TupleExpr            * ) override final;
-	virtual const ast::Expr *             visit( const ast::TupleIndexExpr       * ) override final;
-	virtual const ast::Expr *             visit( const ast::TupleAssignExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::StmtExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::UniqueExpr           * ) override final;
-	virtual const ast::Expr *             visit( const ast::UntypedInitExpr      * ) override final;
-	virtual const ast::Expr *             visit( const ast::InitExpr             * ) override final;
-	virtual const ast::Expr *             visit( const ast::DeletedExpr          * ) override final;
-	virtual const ast::Expr *             visit( const ast::DefaultArgExpr       * ) override final;
-	virtual const ast::Expr *             visit( const ast::GenericExpr          * ) override final;
-	virtual const ast::Type *             visit( const ast::VoidType             * ) override final;
-	virtual const ast::Type *             visit( const ast::BasicType            * ) override final;
-	virtual const ast::Type *             visit( const ast::PointerType          * ) override final;
-	virtual const ast::Type *             visit( const ast::ArrayType            * ) override final;
-	virtual const ast::Type *             visit( const ast::ReferenceType        * ) override final;
-	virtual const ast::Type *             visit( const ast::QualifiedType        * ) override final;
-	virtual const ast::Type *             visit( const ast::FunctionType         * ) override final;
-	virtual const ast::Type *             visit( const ast::StructInstType       * ) override final;
-	virtual const ast::Type *             visit( const ast::UnionInstType        * ) override final;
-	virtual const ast::Type *             visit( const ast::EnumInstType         * ) override final;
-	virtual const ast::Type *             visit( const ast::TraitInstType        * ) override final;
-	virtual const ast::Type *             visit( const ast::TypeInstType         * ) override final;
-	virtual const ast::Type *             visit( const ast::TupleType            * ) override final;
-	virtual const ast::Type *             visit( const ast::TypeofType           * ) override final;
-	virtual const ast::Type *             visit( const ast::AttrType             * ) override final;
-	virtual const ast::Type *             visit( const ast::VarArgsType          * ) override final;
-	virtual const ast::Type *             visit( const ast::ZeroType             * ) override final;
-	virtual const ast::Type *             visit( const ast::OneType              * ) override final;
-	virtual const ast::Type *             visit( const ast::GlobalScopeType      * ) override final;
-	virtual const ast::Designation *      visit( const ast::Designation          * ) override final;
-	virtual const ast::Init *             visit( const ast::SingleInit           * ) override final;
-	virtual const ast::Init *             visit( const ast::ListInit             * ) override final;
-	virtual const ast::Init *             visit( const ast::ConstructorInit      * ) override final;
-	virtual const ast::Constant *         visit( const ast::Constant             * ) override final;
-	virtual const ast::Attribute *        visit( const ast::Attribute            * ) override final;
-	virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
+	const ast::DeclWithType *     visit( const ast::ObjectDecl           * ) override final;
+	const ast::DeclWithType *     visit( const ast::FunctionDecl         * ) override final;
+	const ast::Decl *             visit( const ast::StructDecl           * ) override final;
+	const ast::Decl *             visit( const ast::UnionDecl            * ) override final;
+	const ast::Decl *             visit( const ast::EnumDecl             * ) override final;
+	const ast::Decl *             visit( const ast::TraitDecl            * ) override final;
+	const ast::Decl *             visit( const ast::TypeDecl             * ) override final;
+	const ast::Decl *             visit( const ast::TypedefDecl          * ) override final;
+	const ast::AsmDecl *          visit( const ast::AsmDecl              * ) override final;
+	const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
+	const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
+	const ast::Stmt *             visit( const ast::ExprStmt             * ) override final;
+	const ast::Stmt *             visit( const ast::AsmStmt              * ) override final;
+	const ast::Stmt *             visit( const ast::DirectiveStmt        * ) override final;
+	const ast::Stmt *             visit( const ast::IfStmt               * ) override final;
+	const ast::Stmt *             visit( const ast::WhileStmt            * ) override final;
+	const ast::Stmt *             visit( const ast::ForStmt              * ) override final;
+	const ast::Stmt *             visit( const ast::SwitchStmt           * ) override final;
+	const ast::Stmt *             visit( const ast::CaseStmt             * ) override final;
+	const ast::Stmt *             visit( const ast::BranchStmt           * ) override final;
+	const ast::Stmt *             visit( const ast::ReturnStmt           * ) override final;
+	const ast::Stmt *             visit( const ast::ThrowStmt            * ) override final;
+	const ast::Stmt *             visit( const ast::TryStmt              * ) override final;
+	const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
+	const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
+	const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
+	const ast::Stmt *             visit( const ast::WithStmt             * ) override final;
+	const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
+	const ast::Stmt *             visit( const ast::DeclStmt             * ) override final;
+	const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) override final;
+	const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
+	const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
+	const ast::Expr *             visit( const ast::NameExpr             * ) override final;
+	const ast::Expr *             visit( const ast::AddressExpr          * ) override final;
+	const ast::Expr *             visit( const ast::LabelAddressExpr     * ) override final;
+	const ast::Expr *             visit( const ast::CastExpr             * ) override final;
+	const ast::Expr *             visit( const ast::KeywordCastExpr      * ) override final;
+	const ast::Expr *             visit( const ast::VirtualCastExpr      * ) override final;
+	const ast::Expr *             visit( const ast::UntypedMemberExpr    * ) override final;
+	const ast::Expr *             visit( const ast::MemberExpr           * ) override final;
+	const ast::Expr *             visit( const ast::VariableExpr         * ) override final;
+	const ast::Expr *             visit( const ast::ConstantExpr         * ) override final;
+	const ast::Expr *             visit( const ast::SizeofExpr           * ) override final;
+	const ast::Expr *             visit( const ast::AlignofExpr          * ) override final;
+	const ast::Expr *             visit( const ast::UntypedOffsetofExpr  * ) override final;
+	const ast::Expr *             visit( const ast::OffsetofExpr         * ) override final;
+	const ast::Expr *             visit( const ast::OffsetPackExpr       * ) override final;
+	const ast::Expr *             visit( const ast::AttrExpr             * ) override final;
+	const ast::Expr *             visit( const ast::LogicalExpr          * ) override final;
+	const ast::Expr *             visit( const ast::ConditionalExpr      * ) override final;
+	const ast::Expr *             visit( const ast::CommaExpr            * ) override final;
+	const ast::Expr *             visit( const ast::TypeExpr             * ) override final;
+	const ast::Expr *             visit( const ast::AsmExpr              * ) override final;
+	const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) override final;
+	const ast::Expr *             visit( const ast::ConstructorExpr      * ) override final;
+	const ast::Expr *             visit( const ast::CompoundLiteralExpr  * ) override final;
+	const ast::Expr *             visit( const ast::RangeExpr            * ) override final;
+	const ast::Expr *             visit( const ast::UntypedTupleExpr     * ) override final;
+	const ast::Expr *             visit( const ast::TupleExpr            * ) override final;
+	const ast::Expr *             visit( const ast::TupleIndexExpr       * ) override final;
+	const ast::Expr *             visit( const ast::TupleAssignExpr      * ) override final;
+	const ast::Expr *             visit( const ast::StmtExpr             * ) override final;
+	const ast::Expr *             visit( const ast::UniqueExpr           * ) override final;
+	const ast::Expr *             visit( const ast::UntypedInitExpr      * ) override final;
+	const ast::Expr *             visit( const ast::InitExpr             * ) override final;
+	const ast::Expr *             visit( const ast::DeletedExpr          * ) override final;
+	const ast::Expr *             visit( const ast::DefaultArgExpr       * ) override final;
+	const ast::Expr *             visit( const ast::GenericExpr          * ) override final;
+	const ast::Type *             visit( const ast::VoidType             * ) override final;
+	const ast::Type *             visit( const ast::BasicType            * ) override final;
+	const ast::Type *             visit( const ast::PointerType          * ) override final;
+	const ast::Type *             visit( const ast::ArrayType            * ) override final;
+	const ast::Type *             visit( const ast::ReferenceType        * ) override final;
+	const ast::Type *             visit( const ast::QualifiedType        * ) override final;
+	const ast::Type *             visit( const ast::FunctionType         * ) override final;
+	const ast::Type *             visit( const ast::StructInstType       * ) override final;
+	const ast::Type *             visit( const ast::UnionInstType        * ) override final;
+	const ast::Type *             visit( const ast::EnumInstType         * ) override final;
+	const ast::Type *             visit( const ast::TraitInstType        * ) override final;
+	const ast::Type *             visit( const ast::TypeInstType         * ) override final;
+	const ast::Type *             visit( const ast::TupleType            * ) override final;
+	const ast::Type *             visit( const ast::TypeofType           * ) override final;
+	const ast::Type *             visit( const ast::AttrType             * ) override final;
+	const ast::Type *             visit( const ast::VarArgsType          * ) override final;
+	const ast::Type *             visit( const ast::ZeroType             * ) override final;
+	const ast::Type *             visit( const ast::OneType              * ) override final;
+	const ast::Type *             visit( const ast::GlobalScopeType      * ) override final;
+	const ast::Designation *      visit( const ast::Designation          * ) override final;
+	const ast::Init *             visit( const ast::SingleInit           * ) override final;
+	const ast::Init *             visit( const ast::ListInit             * ) override final;
+	const ast::Init *             visit( const ast::ConstructorInit      * ) override final;
+	const ast::Constant *         visit( const ast::Constant             * ) override final;
+	const ast::Attribute *        visit( const ast::Attribute            * ) override final;
+	const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
 
 	friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_t>& visitor );
@@ -216,4 +216,7 @@
 		Pass<pass_t> & pass;
 	};
+
+private:
+	bool inFunction = false;
 };
 
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Pass.impl.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -158,8 +158,8 @@
 		// These may be modified by subnode but most be restored once we exit this statemnet.
 		ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
-		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > > __old_decls_before( stmts_before );
-		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > > __old_decls_after ( stmts_after  );
-		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > > __old_stmts_before( decls_before );
-		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > > __old_stmts_after ( decls_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
 
 		// Now is the time to actually visit the node
@@ -212,8 +212,8 @@
 
 		// These may be modified by subnode but most be restored once we exit this statemnet.
-		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > > __old_decls_before( stmts_before );
-		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > > __old_decls_after ( stmts_after  );
-		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > > __old_stmts_before( decls_before );
-		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > > __old_stmts_after ( decls_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) >::type > __old_stmts_before( decls_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) >::type > __old_stmts_after ( decls_after  );
 
 		// update pass statitistics
@@ -390,9 +390,9 @@
 		{
 			guard_indexer guard { *this };
-			maybe_accept( node, &ast::ObjectDecl::type );
-		}
-		maybe_accept( node, &ast::ObjectDecl::init          );
-		maybe_accept( node, &ast::ObjectDecl::bitfieldWidth );
-		maybe_accept( node, &ast::ObjectDecl::attributes    );
+			maybe_accept( node, &ObjectDecl::type );
+		}
+		maybe_accept( node, &ObjectDecl::init          );
+		maybe_accept( node, &ObjectDecl::bitfieldWidth );
+		maybe_accept( node, &ObjectDecl::attributes    );
 	)
 
@@ -401,4 +401,217 @@
 	VISIT_END( DeclWithType, node );
 }
+
+//--------------------------------------------------------------------------
+// FunctionDecl
+template< typename pass_t >
+const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
+	VISIT_START( node );
+
+	__pass::indexer::addId( pass, 0, node );
+
+	VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
+	{
+		// with clause introduces a level of scope (for the with expression members).
+		// with clause exprs are added to the indexer before parameters so that parameters
+		// shadow with exprs and not the other way around.
+		guard_indexer guard { *this };
+		__pass::indexer::addWith( pass, 0, node->withExprs, node );
+		{
+			guard_indexer guard { *this };
+			// implicit add __func__ identifier as specified in the C manual 6.4.2.2
+			static ast::ObjectDecl func(
+				node->location, "__func__",
+				new ast::ArrayType(
+					new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
+					nullptr, true, false
+				)
+			);
+			__pass::indexer::addId( pass, 0, &func );
+			VISIT(
+				maybe_accept( node, &FunctionDecl::type );
+				// function body needs to have the same scope as parameters - CompoundStmt will not enter
+				// a new scope if inFunction is true
+				ValueGuard< bool > oldInFunction( inFunction );
+				inFunction = true;
+				maybe_accept( node, &FunctionDecl::statements );
+				maybe_accept( node, &FunctionDecl::attributes );
+			)
+		}
+	}
+
+	VISIT_END( DeclWithType, node );
+}
+
+//--------------------------------------------------------------------------
+// StructDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
+	VISIT_START( node );
+
+	// make up a forward declaration and add it before processing the members
+	// needs to be on the heap because addStruct saves the pointer
+	__pass::indexer::addStructFwd( pass, 0, node );
+
+	VISIT({
+		guard_indexer guard { * this };
+		maybe_accept( node, &StructDecl::parameters );
+		maybe_accept( node, &StructDecl::members    );
+	})
+
+	// this addition replaces the forward declaration
+	__pass::indexer::addStruct( pass, 0, node );
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// UnionDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
+	VISIT_START( node );
+
+	// make up a forward declaration and add it before processing the members
+	__pass::indexer::addUnionFwd( pass, 0, node );
+
+	VISIT({
+		guard_indexer guard { * this };
+		maybe_accept( node, &UnionDecl::parameters );
+		maybe_accept( node, &UnionDecl::members    );
+	})
+
+	__pass::indexer::addUnion( pass, 0, node );
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// EnumDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
+	VISIT_START( node );
+
+	__pass::indexer::addEnum( pass, 0, node );
+
+	VISIT(
+		// unlike structs, traits, and unions, enums inject their members into the global scope
+		maybe_accept( node, &EnumDecl::parameters );
+		maybe_accept( node, &EnumDecl::members    );
+	)
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// TraitDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &TraitDecl::parameters );
+		maybe_accept( node, &TraitDecl::members    );
+	})
+
+	__pass::indexer::addTrait( pass, 0, node );
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &TypeDecl::parameters );
+		maybe_accept( node, &TypeDecl::base       );
+	})
+
+	// see A NOTE ON THE ORDER OF TRAVERSAL, above
+	// note that assertions come after the type is added to the symtab, since they are not part of the type proper
+	// and may depend on the type itself
+	__pass::indexer::addType( pass, 0, node );
+
+	VISIT(
+		maybe_accept( node, &TypeDecl::assertions, *this );
+
+		{
+			guard_indexer guard { *this };
+			maybe_accept( node, &TypeDecl::init );
+		}
+	)
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// TypedefDecl
+template< typename pass_t >
+const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_indexer guard { *this };
+		maybe_accept( node, &TypedefDecl::parameters );
+		maybe_accept( node, &TypedefDecl::base       );
+	})
+
+	__pass::indexer::addType( pass, 0, node );
+
+	maybe_accept( node, &TypedefDecl::assertions );
+
+	VISIT_END( Decl, node );
+}
+
+//--------------------------------------------------------------------------
+// AsmDecl
+template< typename pass_t >
+const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &AsmDecl::stmt );
+	)
+
+	VISIT_END( AsmDecl, node );
+}
+
+//--------------------------------------------------------------------------
+// StaticAssertDecl
+template< typename pass_t >
+const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &StaticAssertDecl::condition );
+		maybe_accept( node, &StaticAssertDecl::msg       );
+	)
+
+	VISIT_END( StaticAssertDecl, node );
+}
+
+//--------------------------------------------------------------------------
+// CompoundStmt
+template< typename pass_t >
+const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
+	VISIT_START( node );
+	VISIT({
+		// do not enter a new scope if inFunction is true - needs to check old state before the assignment
+		auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
+			if ( ! inFunction ) __pass::indexer::enter(pass, 0);
+		}, [this, inFunction = this->inFunction]() {
+			if ( ! inFunction ) __pass::indexer::leave(pass, 0);
+		});
+		ValueGuard< bool > guard2( inFunction );
+		guard_scope guard3 { *this };
+		inFunction = false;
+		maybe_accept( node, &CompoundStmt::kids );
+	})
+	VISIT_END( CompoundStmt, node );
+}
+
 
 //--------------------------------------------------------------------------
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision be567e9e16c2183f460b96b09309ba5c6f87ac4c)
+++ src/AST/Stmt.hpp	(revision 23f99e1d5411939dbd45a0bbb1412b814c387ffa)
@@ -40,7 +40,7 @@
 	Stmt(const Stmt& o) : ParseNode(o), labels(o.labels) {}
 
-	virtual const Stmt* accept( Visitor& v ) const override = 0;
+	const Stmt* accept( Visitor& v ) const override = 0;
 private:
-	virtual Stmt* clone() const override = 0;
+	Stmt* clone() const override = 0;
 };
 
@@ -59,7 +59,7 @@
 	void push_front( Stmt* s ) { kids.emplace_front( s ); }
 
-	virtual const CompoundStmt* accept( Visitor& v ) const override { return v.visit( this ); }
+	const CompoundStmt* accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	virtual CompoundStmt* clone() const override { return new CompoundStmt{ *this }; }
+	CompoundStmt* clone() const override { return new CompoundStmt{ *this }; }
 };
 
@@ -70,7 +70,7 @@
 	: Stmt(loc, std::move(labels)) {}
 
-	virtual const NullStmt * accept( Visitor& v ) const override { return v.visit( this ); }
+	const NullStmt * accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	virtual NullStmt * clone() const override { return new NullStmt{ *this }; }
+	NullStmt * clone() const override { return new NullStmt{ *this }; }
 };
 
@@ -82,7 +82,7 @@
 	ExprStmt( const CodeLocation& loc, Expr* e ) : Stmt(loc), expr(e) {}
 
-	virtual const Stmt * accept( Visitor& v ) const override { return v.visit( this ); }
+	const Stmt * accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	virtual ExprStmt * clone() const override { return new ExprStmt{ *this }; }
+	ExprStmt * clone() const override { return new ExprStmt{ *this }; }
 };
 
