Index: libcfa/src/collections/string.cfa
===================================================================
--- libcfa/src/collections/string.cfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/collections/string.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -157,19 +157,28 @@
 // Comparison
 
-bool ?==?(const string & s, const string & other) {
-    return *s.inner == *other.inner;
-}
-
-bool ?!=?(const string & s, const string & other) {
-    return *s.inner != *other.inner;
-}
-
-bool ?==?(const string & s, const char * other) {
-    return *s.inner == other;
-}
-
-bool ?!=?(const string & s, const char * other) {
-    return *s.inner != other;
-}
+int  cmp (const string &s1, const string &s2) { return cmp(*s1.inner ,  *s2.inner); }
+bool ?==?(const string &s1, const string &s2) { return     *s1.inner == *s2.inner ; }
+bool ?!=?(const string &s1, const string &s2) { return     *s1.inner != *s2.inner ; }
+bool ?>? (const string &s1, const string &s2) { return     *s1.inner >  *s2.inner ; }
+bool ?>=?(const string &s1, const string &s2) { return     *s1.inner >= *s2.inner ; }
+bool ?<=?(const string &s1, const string &s2) { return     *s1.inner <= *s2.inner ; }
+bool ?<? (const string &s1, const string &s2) { return     *s1.inner <  *s2.inner ; }
+
+int  cmp (const string &s1, const char*   s2) { return cmp(*s1.inner ,   s2      ); }
+bool ?==?(const string &s1, const char*   s2) { return     *s1.inner ==  s2       ; }
+bool ?!=?(const string &s1, const char*   s2) { return     *s1.inner !=  s2       ; }
+bool ?>? (const string &s1, const char*   s2) { return     *s1.inner >   s2       ; }
+bool ?>=?(const string &s1, const char*   s2) { return     *s1.inner >=  s2       ; }
+bool ?<=?(const string &s1, const char*   s2) { return     *s1.inner <=  s2       ; }
+bool ?<? (const string &s1, const char*   s2) { return     *s1.inner <   s2       ; }
+
+int  cmp (const char*   s1, const string &s2) { return cmp( s1       ,  *s2.inner); }
+bool ?==?(const char*   s1, const string &s2) { return      s1       == *s2.inner ; }
+bool ?!=?(const char*   s1, const string &s2) { return      s1       != *s2.inner ; }
+bool ?>? (const char*   s1, const string &s2) { return      s1       >  *s2.inner ; }
+bool ?>=?(const char*   s1, const string &s2) { return      s1       >= *s2.inner ; }
+bool ?<=?(const char*   s1, const string &s2) { return      s1       <= *s2.inner ; }
+bool ?<? (const char*   s1, const string &s2) { return      s1       <  *s2.inner ; }
+
 
 ////////////////////////////////////////////////////////
Index: libcfa/src/collections/string.hfa
===================================================================
--- libcfa/src/collections/string.hfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/collections/string.hfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -116,8 +116,28 @@
 
 // Comparisons
-bool ?==?(const string & s, const string & other);
-bool ?!=?(const string & s, const string & other);
-bool ?==?(const string & s, const char * other);
-bool ?!=?(const string & s, const char * other);
+int  cmp (const string &, const string &);
+bool ?==?(const string &, const string &);
+bool ?!=?(const string &, const string &);
+bool ?>? (const string &, const string &);
+bool ?>=?(const string &, const string &);
+bool ?<=?(const string &, const string &);
+bool ?<? (const string &, const string &);
+
+int  cmp (const string &, const char*);
+bool ?==?(const string &, const char*);
+bool ?!=?(const string &, const char*);
+bool ?>? (const string &, const char*);
+bool ?>=?(const string &, const char*);
+bool ?<=?(const string &, const char*);
+bool ?<? (const string &, const char*);
+
+int  cmp (const char*, const string &);
+bool ?==?(const char*, const string &);
+bool ?!=?(const char*, const string &);
+bool ?>? (const char*, const string &);
+bool ?>=?(const char*, const string &);
+bool ?<=?(const char*, const string &);
+bool ?<? (const char*, const string &);
+
 
 // Slicing
Index: libcfa/src/collections/string_res.cfa
===================================================================
--- libcfa/src/collections/string_res.cfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/collections/string_res.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -637,19 +637,42 @@
 // Comparisons
 
-
-bool ?==?(const string_res &s1, const string_res &s2) {
-    return ByteCmp( s1.Handle.s, 0, s1.Handle.lnth, s2.Handle.s, 0, s2.Handle.lnth) == 0;
-}
-
-bool ?!=?(const string_res &s1, const string_res &s2) {
-    return !(s1 == s2);
-}
-bool ?==?(const string_res &s, const char* other) {
-    string_res sother = other;
-    return s == sother;
-}
-bool ?!=?(const string_res &s, const char* other) {
-    return !(s == other);
-}
+int cmp(const string_res &s1, const string_res &s2) {
+    // return 0;
+    int ans1 = memcmp(s1.Handle.s, s2.Handle.s, min(s1.Handle.lnth, s2.Handle.lnth));
+    if (ans1 != 0) return ans1;
+    return s1.Handle.lnth - s2.Handle.lnth;
+}
+
+bool ?==?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) == 0; }
+bool ?!=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) != 0; }
+bool ?>? (const string_res &s1, const string_res &s2) { return cmp(s1, s2) >  0; }
+bool ?>=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) >= 0; }
+bool ?<=?(const string_res &s1, const string_res &s2) { return cmp(s1, s2) <= 0; }
+bool ?<? (const string_res &s1, const string_res &s2) { return cmp(s1, s2) <  0; }
+
+int cmp (const string_res &s1, const char* s2) {
+    string_res s2x = s2;
+    return cmp(s1, s2x);
+}
+
+bool ?==?(const string_res &s1, const char* s2) { return cmp(s1, s2) == 0; }
+bool ?!=?(const string_res &s1, const char* s2) { return cmp(s1, s2) != 0; }
+bool ?>? (const string_res &s1, const char* s2) { return cmp(s1, s2) >  0; }
+bool ?>=?(const string_res &s1, const char* s2) { return cmp(s1, s2) >= 0; }
+bool ?<=?(const string_res &s1, const char* s2) { return cmp(s1, s2) <= 0; }
+bool ?<? (const string_res &s1, const char* s2) { return cmp(s1, s2) <  0; }
+
+int cmp (const char* s1, const string_res & s2) {
+    string_res s1x = s1;
+    return cmp(s1x, s2);
+}
+
+bool ?==?(const char* s1, const string_res &s2) { return cmp(s1, s2) == 0; }
+bool ?!=?(const char* s1, const string_res &s2) { return cmp(s1, s2) != 0; }
+bool ?>? (const char* s1, const string_res &s2) { return cmp(s1, s2) >  0; }
+bool ?>=?(const char* s1, const string_res &s2) { return cmp(s1, s2) >= 0; }
+bool ?<=?(const char* s1, const string_res &s2) { return cmp(s1, s2) <= 0; }
+bool ?<? (const char* s1, const string_res &s2) { return cmp(s1, s2) <  0; }
+
 
 
Index: libcfa/src/collections/string_res.hfa
===================================================================
--- libcfa/src/collections/string_res.hfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/collections/string_res.hfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -142,8 +142,27 @@
 
 // Comparisons
-bool ?==?(const string_res &s, const string_res &other);
-bool ?!=?(const string_res &s, const string_res &other);
-bool ?==?(const string_res &s, const char* other);
-bool ?!=?(const string_res &s, const char* other);
+int  cmp (const string_res &, const string_res &);
+bool ?==?(const string_res &, const string_res &);
+bool ?!=?(const string_res &, const string_res &);
+bool ?>? (const string_res &, const string_res &);
+bool ?>=?(const string_res &, const string_res &);
+bool ?<=?(const string_res &, const string_res &);
+bool ?<? (const string_res &, const string_res &);
+
+int  cmp (const string_res &, const char*);
+bool ?==?(const string_res &, const char*);
+bool ?!=?(const string_res &, const char*);
+bool ?>? (const string_res &, const char*);
+bool ?>=?(const string_res &, const char*);
+bool ?<=?(const string_res &, const char*);
+bool ?<? (const string_res &, const char*);
+
+int  cmp (const char*, const string_res &);
+bool ?==?(const char*, const string_res &);
+bool ?!=?(const char*, const string_res &);
+bool ?>? (const char*, const string_res &);
+bool ?>=?(const char*, const string_res &);
+bool ?<=?(const char*, const string_res &);
+bool ?<? (const char*, const string_res &);
 
 // String search
Index: libcfa/src/concurrency/io.cfa
===================================================================
--- libcfa/src/concurrency/io.cfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/concurrency/io.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -594,8 +594,8 @@
 		lock( queue.lock __cfaabi_dbg_ctx2 );
 		{
-			was_empty = empty(queue.queue);
+			was_empty = queue.queue`isEmpty;
 
 			// Add our request to the list
-			add( queue.queue, item );
+			insert_last( queue.queue, item );
 
 			// Mark as pending
@@ -632,5 +632,5 @@
 	// notify the arbiter that new allocations are available
 	static void __ioarbiter_notify( io_arbiter$ & this, io_context$ * ctx ) {
-		/* paranoid */ verify( !empty(this.pending.queue) );
+		/* paranoid */ verify( !this.pending.queue`isEmpty );
 		/* paranoid */ verify( __preemption_enabled() );
 
@@ -642,8 +642,8 @@
 			// as long as there are pending allocations try to satisfy them
 			// for simplicity do it in FIFO order
-			while( !empty(this.pending.queue) ) {
+			while( !this.pending.queue`isEmpty ) {
 				// get first pending allocs
 				__u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head;
-				__pending_alloc & pa = (__pending_alloc&)head( this.pending.queue );
+				__pending_alloc & pa = (__pending_alloc&)(this.pending.queue`first);
 
 				// check if we have enough to satisfy the request
@@ -651,5 +651,5 @@
 
 				// if there are enough allocations it means we can drop the request
-				drop( this.pending.queue );
+				try_pop_front( this.pending.queue );
 
 				/* paranoid */__attribute__((unused)) bool ret =
@@ -727,7 +727,7 @@
 			// pop each operation one at a time.
 			// There is no wait morphing because of the io sq ring
-			while( !empty(ctx.ext_sq.queue) ) {
+			while( !ctx.ext_sq.queue`isEmpty ) {
 				// drop the element from the queue
-				__external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
+				__external_io & ei = (__external_io&)try_pop_front( ctx.ext_sq.queue );
 
 				// submit it
Index: libcfa/src/concurrency/io/types.hfa
===================================================================
--- libcfa/src/concurrency/io/types.hfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/concurrency/io/types.hfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -24,10 +24,8 @@
 
 #include "bits/locks.hfa"
-#include "bits/queue.hfa"
 #include "iofwd.hfa"
 #include "kernel/fwd.hfa"
 
 #if defined(CFA_HAVE_LINUX_IO_URING_H)
-	#include "bits/sequence.hfa"
 	#include "monitor.hfa"
 
@@ -120,10 +118,10 @@
 	struct __outstanding_io {
 		// intrusive link fields
-		inline Colable;
+		inline dlink(__outstanding_io);
 
 		// primitive on which to block until the io is processed
 		oneshot waitctx;
 	};
-	static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); }
+    P9_EMBEDDED( __outstanding_io, dlink(__outstanding_io) )
 
 	// queue of operations that are outstanding
@@ -134,5 +132,5 @@
 
 		// the actual queue
-		Queue(__outstanding_io) queue;
+		dlist(__outstanding_io) queue;
 
 		// volatile used to avoid the need for taking the lock if it's empty
Index: libcfa/src/concurrency/pthread.cfa
===================================================================
--- libcfa/src/concurrency/pthread.cfa	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ libcfa/src/concurrency/pthread.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -20,7 +20,4 @@
 #include <errno.h>
 #include "locks.hfa"
-#include "bits/stack.hfa"
-#include "bits/sequence.hfa"
-
 
 #define check_nonnull(x) asm("": "+rm"(x)); if( x == 0p ) return EINVAL;
@@ -34,23 +31,14 @@
 
 struct pthread_values{
-	inline Seqable;
+	inline dlink(pthread_values);
 	void * value;
 	bool in_use;
 };
-
-static inline {
-	pthread_values *& Back( pthread_values * n ) {
-		return (pthread_values *)Back( (Seqable *)n );
-	}
-
-	pthread_values *& Next( pthread_values * n ) {
-		return (pthread_values *)Next( (Colable *)n );
-	}
-}
+P9_EMBEDDED( pthread_values, dlink(pthread_values) )
 
 struct pthread_keys {
 	bool in_use;
 	void (* destructor)( void * );
-	Sequence(pthread_values) threads;
+    dlist( pthread_values ) threads;
 };
 
@@ -78,13 +66,10 @@
 
 struct Pthread_kernel_threads{
-	inline Colable;
+	inline dlink(Pthread_kernel_threads);
 	processor p;
 };
-
-Pthread_kernel_threads *& Next( Pthread_kernel_threads * n ) {
-	return (Pthread_kernel_threads *)Next( (Colable *)n );
-}
-
-static Stack(Pthread_kernel_threads) cfa_pthreads_kernel_threads;
+P9_EMBEDDED( Pthread_kernel_threads, dlink(Pthread_kernel_threads) )
+
+static dlist(Pthread_kernel_threads) cfa_pthreads_kernel_threads;
 static bool cfa_pthreads_kernel_threads_zero = false;	// set to zero ?
 static int cfa_pthreads_no_kernel_threads = 1;	// number of kernel threads
@@ -231,5 +216,6 @@
 					key = &cfa_pthread_keys[i];
 					value->in_use = false;
-					remove(key->threads, *value);
+					remove(*value);
+
 					// if  a  key  value  has  a  non-NULL  destructor pointer,  and  the  thread  has  a  non-NULL  value associated with that key,
 					// the value of the key is set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.
@@ -551,10 +537,15 @@
 
 		// Remove key from all threads with a value.
-		pthread_values& p;
-		Sequence(pthread_values)& head = cfa_pthread_keys[key].threads;
-		for ( SeqIter(pthread_values) iter = { head }; iter | p; ) {
-			remove(head, p);
-			p.in_use = false;
-		}
+		
+		// Sequence(pthread_values)& head = cfa_pthread_keys[key].threads;
+		// for ( SeqIter(pthread_values) iter = { head }; iter | p; ) {
+		// 	remove(head, p);
+		// 	p.in_use = false;
+		// }
+        pthread_values * p = &try_pop_front( cfa_pthread_keys[key].threads );
+        for ( ; p; ) {            
+            p->in_use = false;
+            p = &try_pop_front( cfa_pthread_keys[key].threads );
+        }
 		unlock(key_lock);
 		return 0;
@@ -585,5 +576,5 @@
 		if ( ! entry.in_use ) {
 			entry.in_use = true;
-			add(cfa_pthread_keys[key].threads, entry);
+			insert_last(cfa_pthread_keys[key].threads, entry);
 		} // if
 		entry.value = (void *)value;
@@ -612,7 +603,8 @@
 	//######################### Parallelism #########################
 	void pthread_delete_kernel_threads_() __THROW {	// see uMain::~uMain
-		Pthread_kernel_threads& p;
-		for ( StackIter(Pthread_kernel_threads) iter = {cfa_pthreads_kernel_threads}; iter | p; ) {
-			delete(&p);
+		Pthread_kernel_threads * p = &try_pop_front(cfa_pthreads_kernel_threads);
+		for ( ; p; ) {
+            delete(p);
+			p = &try_pop_front(cfa_pthreads_kernel_threads);
 		} // for
 	} // pthread_delete_kernel_threads_
@@ -631,8 +623,8 @@
 		lock( concurrency_lock );
 		for ( ; new_level > cfa_pthreads_no_kernel_threads; cfa_pthreads_no_kernel_threads += 1 ) { // add processors ?
-			push(cfa_pthreads_kernel_threads, *new() );
+			insert_last(cfa_pthreads_kernel_threads, *new() );
 		} // for
 		for ( ; new_level < cfa_pthreads_no_kernel_threads; cfa_pthreads_no_kernel_threads -= 1 ) { // remove processors ?
-			delete(&pop(cfa_pthreads_kernel_threads));
+			delete(&try_pop_front(cfa_pthreads_kernel_threads));
 		} // for
 		unlock( concurrency_lock );
Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov  1 13:48:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Mar 28  9:42:00 2022
-// Update Count     : 34
+// Last Modified On : Wed Sep  6 12:00:00 2023
+// Update Count     : 35
 //
 
@@ -18,5 +18,4 @@
 #include "AST/Pass.hpp"
 #include "AST/Stmt.hpp"
-#include "Common/CodeLocationTools.hpp"
 #include "LabelGeneratorNew.hpp"
 
@@ -26,4 +25,7 @@
 
 namespace ControlStruct {
+
+namespace {
+
 class Entry {
   public:
@@ -35,5 +37,5 @@
 		bool used = false;
 		Target( const Label & label ) : label( label ) {}
-		Target() : label( CodeLocation() ) {}
+		Target() : label( CodeLocation(), "" ) {}
 	};
 	Target firstTarget;
@@ -524,17 +526,12 @@
 	// if continue is used insert a continue label into the back of the body of the loop
 	if ( entry.isContUsed() ) {
-		CompoundStmt * new_body = new CompoundStmt( body->location );
-		// {}
-		new_body->kids.push_back( body );
 		// {
 		//  body
+		//  ContinueLabel: ;
 		// }
-		new_body->kids.push_back(
-			labelledNullStmt( body->location, entry.useContExit() ) );
-		// {
-		//  body
-		//  ContinueLabel: {}
-		// }
-		return new_body;
+		return new CompoundStmt( body->location, {
+			body,
+			labelledNullStmt( body->location, entry.useContExit() ),
+		} );
 	}
 
@@ -620,14 +617,13 @@
 }
 
+} // namespace
+
 const CompoundStmt * multiLevelExitUpdate(
-	const CompoundStmt * stmt,
-	const LabelToStmt & labelTable ) {
+		const CompoundStmt * stmt, const LabelToStmt & labelTable ) {
 	// Must start in the body, so FunctionDecls can be a stopping point.
 	Pass<MultiLevelExitCore> visitor( labelTable );
-	const CompoundStmt * ret = stmt->accept( visitor );
-	// There are some unset code locations slipping in, possibly by Labels.
-	const Node * node = localFillCodeLocations( ret->location, ret );
-	return strict_dynamic_cast<const CompoundStmt *>( node );
-}
+	return stmt->accept( visitor );
+}
+
 } // namespace ControlStruct
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -237,5 +237,6 @@
             // The designator I want to replace
             const ast::Expr * designator = des->designators.at(0);
-
+            // Stupid flag variable for development, to be removed
+            bool mutated = false;
             if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
                 auto candidates = context.symtab.lookupId(designatorName->name);
@@ -244,5 +245,5 @@
                 if ( candidates.size() != 1 ) return mutDecl;
                 auto candidate = candidates.at(0);
-                if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
+                if ( const ast::EnumInstType * enumInst = dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type())) {
                     // determine that is an enumInst, swap it with its const value
                     assert( candidates.size() == 1 );
@@ -250,13 +251,15 @@
                     // Need to iterate over all enum value to find the initializer to swap
                     for ( size_t m = 0; m < baseEnum->members.size(); ++m ) {
+                        const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
                         if ( baseEnum->members.at(m)->name == designatorName->name ) {
-                            const ast::ObjectDecl * mem = baseEnum->members.at(m).as<const ast::ObjectDecl>();
                             assert(mem);
-                            const ast::ConstantExpr * enumAsInit = ast::ConstantExpr::from_int(newDesination->location, m);
-                            newDesination->designators.push_back( enumAsInit );
+                            if ( mem->init ) {
+                                const ast::SingleInit * memInit = mem->init.as<const ast::SingleInit>();
+                                ast::Expr * initValue = shallowCopy( memInit->value.get() );
+                                newDesination->designators.push_back( initValue );
+                                mutated = true;
+                            }
+                            break;
                         }
-                    }
-                    if ( newDesination->designators.size() == 0 ) {
-                        SemanticError(des->location, "Resolution Error: Resolving array designation as Enum Instance value, but cannot find a desgination value");
                     }
                 } else {
@@ -266,5 +269,7 @@
                 newDesination->designators.push_back( des->designators.at(0) );
             }
-            mutListInit = ast::mutate_field_index(mutListInit, &ast::ListInit::designations, k, newDesination);
+            if ( mutated ) {
+                mutListInit = ast::mutate_field_index(mutListInit, &ast::ListInit::designations, k, newDesination);
+            }
         }
     }
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 79b052241260d5f8af60352f0c9315c007c9c8de)
+++ src/ResolvExpr/Resolver.cc	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -988,4 +988,35 @@
 			}
 		};
+
+		struct ResolveDesignators_new final : public ast::WithShortCircuiting {
+			ResolveContext& context;
+			bool result = false;
+
+			ResolveDesignators_new( ResolveContext& _context ): context{_context} {};
+
+			void previsit( const ast::Node * ) {
+				// short circuit if we already know there are designations
+				if ( result ) visit_children = false;
+			}
+
+			void previsit( const ast::Designation * des ) {
+				if ( result ) visit_children = false;
+				else if ( ! des->designators.empty() ) {
+					if ( (des->designators.size() == 1) ) {
+						const ast::Expr * designator = des->designators.at(0);
+						if ( const ast::NameExpr * designatorName = dynamic_cast<const ast::NameExpr *>(designator) ) {
+							auto candidates = context.symtab.lookupId(designatorName->name);
+							for ( auto candidate : candidates ) {
+								if ( dynamic_cast<const ast::EnumInstType *>(candidate.id->get_type()) ) {
+									result = true;
+									break;
+								}
+							}
+						} 
+					} 
+					visit_children = false;
+				}
+			}
+		};
 	} // anonymous namespace
 	/// Check if this expression is or includes a deleted expression
@@ -1507,7 +1538,10 @@
 				if ( InitTweak::tryConstruct( mutDecl ) && ( managedTypes.isManaged( mutDecl ) || ((! isInFunction() || mutDecl->storage.is_static ) && ! InitTweak::isConstExpr( mutDecl->init ) ) ) ) {
 					// constructed objects cannot be designated
-					// if ( InitTweak::isDesignated( mutDecl->init ) ) SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
 					if ( InitTweak::isDesignated( mutDecl->init ) ) {
-						SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
+						ast::Pass<ResolveDesignators_new> res( context );
+						maybe_accept( mutDecl->init.get(), res );
+						if ( !res.core.result ) {
+							SemanticError( mutDecl, "Cannot include designations in the initializer for a managed Object. If this is really what you want, then initialize with @=.\n" );
+						}
 					}
 					// constructed objects should not have initializers nested too deeply
Index: tests/collections/.expect/string-compare.txt
===================================================================
--- tests/collections/.expect/string-compare.txt	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
+++ tests/collections/.expect/string-compare.txt	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -0,0 +1,800 @@
+------- string -------
+(cmp(s_, s_) == 0) ok
+(s_ == s_) ok
+!(s_ != s_) ok
+!(s_ > s_) ok
+(s_ >= s_) ok
+(s_ <= s_) ok
+!(s_ < s_) ok
+(cmp("", s_) == 0) ok
+("" == s_) ok
+!("" != s_) ok
+!("" > s_) ok
+("" >= s_) ok
+("" <= s_) ok
+!("" < s_) ok
+(cmp(s_, "") == 0) ok
+(s_ == "") ok
+!(s_ != "") ok
+!(s_ > "") ok
+(s_ >= "") ok
+(s_ <= "") ok
+!(s_ < "") ok
+(cmp(s_, s_a) < 0) ok
+!(s_ == s_a) ok
+(s_ != s_a) ok
+!(s_ > s_a) ok
+!(s_ >= s_a) ok
+(s_ <= s_a) ok
+(s_ < s_a) ok
+(cmp("", s_a) < 0) ok
+!("" == s_a) ok
+("" != s_a) ok
+!("" > s_a) ok
+!("" >= s_a) ok
+("" <= s_a) ok
+("" < s_a) ok
+(cmp(s_, "a") < 0) ok
+!(s_ == "a") ok
+(s_ != "a") ok
+!(s_ > "a") ok
+!(s_ >= "a") ok
+(s_ <= "a") ok
+(s_ < "a") ok
+(cmp(s_a, s_) > 0) ok
+!(s_a == s_) ok
+(s_a != s_) ok
+(s_a > s_) ok
+(s_a >= s_) ok
+!(s_a <= s_) ok
+!(s_a < s_) ok
+(cmp("a", s_) > 0) ok
+!("a" == s_) ok
+("a" != s_) ok
+("a" > s_) ok
+("a" >= s_) ok
+!("a" <= s_) ok
+!("a" < s_) ok
+(cmp(s_a, "") > 0) ok
+!(s_a == "") ok
+(s_a != "") ok
+(s_a > "") ok
+(s_a >= "") ok
+!(s_a <= "") ok
+!(s_a < "") ok
+(cmp(s_, s_aa) < 0) ok
+!(s_ == s_aa) ok
+(s_ != s_aa) ok
+!(s_ > s_aa) ok
+!(s_ >= s_aa) ok
+(s_ <= s_aa) ok
+(s_ < s_aa) ok
+(cmp("", s_aa) < 0) ok
+!("" == s_aa) ok
+("" != s_aa) ok
+!("" > s_aa) ok
+!("" >= s_aa) ok
+("" <= s_aa) ok
+("" < s_aa) ok
+(cmp(s_, "aa") < 0) ok
+!(s_ == "aa") ok
+(s_ != "aa") ok
+!(s_ > "aa") ok
+!(s_ >= "aa") ok
+(s_ <= "aa") ok
+(s_ < "aa") ok
+(cmp(s_aa, s_) > 0) ok
+!(s_aa == s_) ok
+(s_aa != s_) ok
+(s_aa > s_) ok
+(s_aa >= s_) ok
+!(s_aa <= s_) ok
+!(s_aa < s_) ok
+(cmp("aa", s_) > 0) ok
+!("aa" == s_) ok
+("aa" != s_) ok
+("aa" > s_) ok
+("aa" >= s_) ok
+!("aa" <= s_) ok
+!("aa" < s_) ok
+(cmp(s_aa, "") > 0) ok
+!(s_aa == "") ok
+(s_aa != "") ok
+(s_aa > "") ok
+(s_aa >= "") ok
+!(s_aa <= "") ok
+!(s_aa < "") ok
+(cmp(s_a, s_aa) < 0) ok
+!(s_a == s_aa) ok
+(s_a != s_aa) ok
+!(s_a > s_aa) ok
+!(s_a >= s_aa) ok
+(s_a <= s_aa) ok
+(s_a < s_aa) ok
+(cmp("a", s_aa) < 0) ok
+!("a" == s_aa) ok
+("a" != s_aa) ok
+!("a" > s_aa) ok
+!("a" >= s_aa) ok
+("a" <= s_aa) ok
+("a" < s_aa) ok
+(cmp(s_a, "aa") < 0) ok
+!(s_a == "aa") ok
+(s_a != "aa") ok
+!(s_a > "aa") ok
+!(s_a >= "aa") ok
+(s_a <= "aa") ok
+(s_a < "aa") ok
+(cmp(s_aa, s_a) > 0) ok
+!(s_aa == s_a) ok
+(s_aa != s_a) ok
+(s_aa > s_a) ok
+(s_aa >= s_a) ok
+!(s_aa <= s_a) ok
+!(s_aa < s_a) ok
+(cmp("aa", s_a) > 0) ok
+!("aa" == s_a) ok
+("aa" != s_a) ok
+("aa" > s_a) ok
+("aa" >= s_a) ok
+!("aa" <= s_a) ok
+!("aa" < s_a) ok
+(cmp(s_aa, "a") > 0) ok
+!(s_aa == "a") ok
+(s_aa != "a") ok
+(s_aa > "a") ok
+(s_aa >= "a") ok
+!(s_aa <= "a") ok
+!(s_aa < "a") ok
+(cmp(s_a, s_a) == 0) ok
+(s_a == s_a) ok
+!(s_a != s_a) ok
+!(s_a > s_a) ok
+(s_a >= s_a) ok
+(s_a <= s_a) ok
+!(s_a < s_a) ok
+(cmp("a", s_a) == 0) ok
+("a" == s_a) ok
+!("a" != s_a) ok
+!("a" > s_a) ok
+("a" >= s_a) ok
+("a" <= s_a) ok
+!("a" < s_a) ok
+(cmp(s_a, "a") == 0) ok
+(s_a == "a") ok
+!(s_a != "a") ok
+!(s_a > "a") ok
+(s_a >= "a") ok
+(s_a <= "a") ok
+!(s_a < "a") ok
+(cmp(s_aa, s_aa) == 0) ok
+(s_aa == s_aa) ok
+!(s_aa != s_aa) ok
+!(s_aa > s_aa) ok
+(s_aa >= s_aa) ok
+(s_aa <= s_aa) ok
+!(s_aa < s_aa) ok
+(cmp("aa", s_aa) == 0) ok
+("aa" == s_aa) ok
+!("aa" != s_aa) ok
+!("aa" > s_aa) ok
+("aa" >= s_aa) ok
+("aa" <= s_aa) ok
+!("aa" < s_aa) ok
+(cmp(s_aa, "aa") == 0) ok
+(s_aa == "aa") ok
+!(s_aa != "aa") ok
+!(s_aa > "aa") ok
+(s_aa >= "aa") ok
+(s_aa <= "aa") ok
+!(s_aa < "aa") ok
+(cmp(s_a, s_b) < 0) ok
+!(s_a == s_b) ok
+(s_a != s_b) ok
+!(s_a > s_b) ok
+!(s_a >= s_b) ok
+(s_a <= s_b) ok
+(s_a < s_b) ok
+(cmp("a", s_b) < 0) ok
+!("a" == s_b) ok
+("a" != s_b) ok
+!("a" > s_b) ok
+!("a" >= s_b) ok
+("a" <= s_b) ok
+("a" < s_b) ok
+(cmp(s_a, "b") < 0) ok
+!(s_a == "b") ok
+(s_a != "b") ok
+!(s_a > "b") ok
+!(s_a >= "b") ok
+(s_a <= "b") ok
+(s_a < "b") ok
+(cmp(s_b, s_a) > 0) ok
+!(s_b == s_a) ok
+(s_b != s_a) ok
+(s_b > s_a) ok
+(s_b >= s_a) ok
+!(s_b <= s_a) ok
+!(s_b < s_a) ok
+(cmp("b", s_a) > 0) ok
+!("b" == s_a) ok
+("b" != s_a) ok
+("b" > s_a) ok
+("b" >= s_a) ok
+!("b" <= s_a) ok
+!("b" < s_a) ok
+(cmp(s_b, "a") > 0) ok
+!(s_b == "a") ok
+(s_b != "a") ok
+(s_b > "a") ok
+(s_b >= "a") ok
+!(s_b <= "a") ok
+!(s_b < "a") ok
+(cmp(s_a, s_ba) < 0) ok
+!(s_a == s_ba) ok
+(s_a != s_ba) ok
+!(s_a > s_ba) ok
+!(s_a >= s_ba) ok
+(s_a <= s_ba) ok
+(s_a < s_ba) ok
+(cmp("a", s_ba) < 0) ok
+!("a" == s_ba) ok
+("a" != s_ba) ok
+!("a" > s_ba) ok
+!("a" >= s_ba) ok
+("a" <= s_ba) ok
+("a" < s_ba) ok
+(cmp(s_a, "ba") < 0) ok
+!(s_a == "ba") ok
+(s_a != "ba") ok
+!(s_a > "ba") ok
+!(s_a >= "ba") ok
+(s_a <= "ba") ok
+(s_a < "ba") ok
+(cmp(s_ba, s_a) > 0) ok
+!(s_ba == s_a) ok
+(s_ba != s_a) ok
+(s_ba > s_a) ok
+(s_ba >= s_a) ok
+!(s_ba <= s_a) ok
+!(s_ba < s_a) ok
+(cmp("ba", s_a) > 0) ok
+!("ba" == s_a) ok
+("ba" != s_a) ok
+("ba" > s_a) ok
+("ba" >= s_a) ok
+!("ba" <= s_a) ok
+!("ba" < s_a) ok
+(cmp(s_ba, "a") > 0) ok
+!(s_ba == "a") ok
+(s_ba != "a") ok
+(s_ba > "a") ok
+(s_ba >= "a") ok
+!(s_ba <= "a") ok
+!(s_ba < "a") ok
+(cmp(s_aa, s_ab) < 0) ok
+!(s_aa == s_ab) ok
+(s_aa != s_ab) ok
+!(s_aa > s_ab) ok
+!(s_aa >= s_ab) ok
+(s_aa <= s_ab) ok
+(s_aa < s_ab) ok
+(cmp("aa", s_ab) < 0) ok
+!("aa" == s_ab) ok
+("aa" != s_ab) ok
+!("aa" > s_ab) ok
+!("aa" >= s_ab) ok
+("aa" <= s_ab) ok
+("aa" < s_ab) ok
+(cmp(s_aa, "ab") < 0) ok
+!(s_aa == "ab") ok
+(s_aa != "ab") ok
+!(s_aa > "ab") ok
+!(s_aa >= "ab") ok
+(s_aa <= "ab") ok
+(s_aa < "ab") ok
+(cmp(s_ab, s_aa) > 0) ok
+!(s_ab == s_aa) ok
+(s_ab != s_aa) ok
+(s_ab > s_aa) ok
+(s_ab >= s_aa) ok
+!(s_ab <= s_aa) ok
+!(s_ab < s_aa) ok
+(cmp("ab", s_aa) > 0) ok
+!("ab" == s_aa) ok
+("ab" != s_aa) ok
+("ab" > s_aa) ok
+("ab" >= s_aa) ok
+!("ab" <= s_aa) ok
+!("ab" < s_aa) ok
+(cmp(s_ab, "aa") > 0) ok
+!(s_ab == "aa") ok
+(s_ab != "aa") ok
+(s_ab > "aa") ok
+(s_ab >= "aa") ok
+!(s_ab <= "aa") ok
+!(s_ab < "aa") ok
+(cmp(s_ba, s_bb) < 0) ok
+!(s_ba == s_bb) ok
+(s_ba != s_bb) ok
+!(s_ba > s_bb) ok
+!(s_ba >= s_bb) ok
+(s_ba <= s_bb) ok
+(s_ba < s_bb) ok
+(cmp("ba", s_bb) < 0) ok
+!("ba" == s_bb) ok
+("ba" != s_bb) ok
+!("ba" > s_bb) ok
+!("ba" >= s_bb) ok
+("ba" <= s_bb) ok
+("ba" < s_bb) ok
+(cmp(s_ba, "bb") < 0) ok
+!(s_ba == "bb") ok
+(s_ba != "bb") ok
+!(s_ba > "bb") ok
+!(s_ba >= "bb") ok
+(s_ba <= "bb") ok
+(s_ba < "bb") ok
+(cmp(s_bb, s_ba) > 0) ok
+!(s_bb == s_ba) ok
+(s_bb != s_ba) ok
+(s_bb > s_ba) ok
+(s_bb >= s_ba) ok
+!(s_bb <= s_ba) ok
+!(s_bb < s_ba) ok
+(cmp("bb", s_ba) > 0) ok
+!("bb" == s_ba) ok
+("bb" != s_ba) ok
+("bb" > s_ba) ok
+("bb" >= s_ba) ok
+!("bb" <= s_ba) ok
+!("bb" < s_ba) ok
+(cmp(s_bb, "ba") > 0) ok
+!(s_bb == "ba") ok
+(s_bb != "ba") ok
+(s_bb > "ba") ok
+(s_bb >= "ba") ok
+!(s_bb <= "ba") ok
+!(s_bb < "ba") ok
+(cmp(s_aa, s_b) < 0) ok
+!(s_aa == s_b) ok
+(s_aa != s_b) ok
+!(s_aa > s_b) ok
+!(s_aa >= s_b) ok
+(s_aa <= s_b) ok
+(s_aa < s_b) ok
+(cmp("aa", s_b) < 0) ok
+!("aa" == s_b) ok
+("aa" != s_b) ok
+!("aa" > s_b) ok
+!("aa" >= s_b) ok
+("aa" <= s_b) ok
+("aa" < s_b) ok
+(cmp(s_aa, "b") < 0) ok
+!(s_aa == "b") ok
+(s_aa != "b") ok
+!(s_aa > "b") ok
+!(s_aa >= "b") ok
+(s_aa <= "b") ok
+(s_aa < "b") ok
+(cmp(s_b, s_aa) > 0) ok
+!(s_b == s_aa) ok
+(s_b != s_aa) ok
+(s_b > s_aa) ok
+(s_b >= s_aa) ok
+!(s_b <= s_aa) ok
+!(s_b < s_aa) ok
+(cmp("b", s_aa) > 0) ok
+!("b" == s_aa) ok
+("b" != s_aa) ok
+("b" > s_aa) ok
+("b" >= s_aa) ok
+!("b" <= s_aa) ok
+!("b" < s_aa) ok
+(cmp(s_b, "aa") > 0) ok
+!(s_b == "aa") ok
+(s_b != "aa") ok
+(s_b > "aa") ok
+(s_b >= "aa") ok
+!(s_b <= "aa") ok
+!(s_b < "aa") ok
+------- string_res -------
+(cmp(s_, s_) == 0) ok
+(s_ == s_) ok
+!(s_ != s_) ok
+!(s_ > s_) ok
+(s_ >= s_) ok
+(s_ <= s_) ok
+!(s_ < s_) ok
+(cmp("", s_) == 0) ok
+("" == s_) ok
+!("" != s_) ok
+!("" > s_) ok
+("" >= s_) ok
+("" <= s_) ok
+!("" < s_) ok
+(cmp(s_, "") == 0) ok
+(s_ == "") ok
+!(s_ != "") ok
+!(s_ > "") ok
+(s_ >= "") ok
+(s_ <= "") ok
+!(s_ < "") ok
+(cmp(s_, s_a) < 0) ok
+!(s_ == s_a) ok
+(s_ != s_a) ok
+!(s_ > s_a) ok
+!(s_ >= s_a) ok
+(s_ <= s_a) ok
+(s_ < s_a) ok
+(cmp("", s_a) < 0) ok
+!("" == s_a) ok
+("" != s_a) ok
+!("" > s_a) ok
+!("" >= s_a) ok
+("" <= s_a) ok
+("" < s_a) ok
+(cmp(s_, "a") < 0) ok
+!(s_ == "a") ok
+(s_ != "a") ok
+!(s_ > "a") ok
+!(s_ >= "a") ok
+(s_ <= "a") ok
+(s_ < "a") ok
+(cmp(s_a, s_) > 0) ok
+!(s_a == s_) ok
+(s_a != s_) ok
+(s_a > s_) ok
+(s_a >= s_) ok
+!(s_a <= s_) ok
+!(s_a < s_) ok
+(cmp("a", s_) > 0) ok
+!("a" == s_) ok
+("a" != s_) ok
+("a" > s_) ok
+("a" >= s_) ok
+!("a" <= s_) ok
+!("a" < s_) ok
+(cmp(s_a, "") > 0) ok
+!(s_a == "") ok
+(s_a != "") ok
+(s_a > "") ok
+(s_a >= "") ok
+!(s_a <= "") ok
+!(s_a < "") ok
+(cmp(s_, s_aa) < 0) ok
+!(s_ == s_aa) ok
+(s_ != s_aa) ok
+!(s_ > s_aa) ok
+!(s_ >= s_aa) ok
+(s_ <= s_aa) ok
+(s_ < s_aa) ok
+(cmp("", s_aa) < 0) ok
+!("" == s_aa) ok
+("" != s_aa) ok
+!("" > s_aa) ok
+!("" >= s_aa) ok
+("" <= s_aa) ok
+("" < s_aa) ok
+(cmp(s_, "aa") < 0) ok
+!(s_ == "aa") ok
+(s_ != "aa") ok
+!(s_ > "aa") ok
+!(s_ >= "aa") ok
+(s_ <= "aa") ok
+(s_ < "aa") ok
+(cmp(s_aa, s_) > 0) ok
+!(s_aa == s_) ok
+(s_aa != s_) ok
+(s_aa > s_) ok
+(s_aa >= s_) ok
+!(s_aa <= s_) ok
+!(s_aa < s_) ok
+(cmp("aa", s_) > 0) ok
+!("aa" == s_) ok
+("aa" != s_) ok
+("aa" > s_) ok
+("aa" >= s_) ok
+!("aa" <= s_) ok
+!("aa" < s_) ok
+(cmp(s_aa, "") > 0) ok
+!(s_aa == "") ok
+(s_aa != "") ok
+(s_aa > "") ok
+(s_aa >= "") ok
+!(s_aa <= "") ok
+!(s_aa < "") ok
+(cmp(s_a, s_aa) < 0) ok
+!(s_a == s_aa) ok
+(s_a != s_aa) ok
+!(s_a > s_aa) ok
+!(s_a >= s_aa) ok
+(s_a <= s_aa) ok
+(s_a < s_aa) ok
+(cmp("a", s_aa) < 0) ok
+!("a" == s_aa) ok
+("a" != s_aa) ok
+!("a" > s_aa) ok
+!("a" >= s_aa) ok
+("a" <= s_aa) ok
+("a" < s_aa) ok
+(cmp(s_a, "aa") < 0) ok
+!(s_a == "aa") ok
+(s_a != "aa") ok
+!(s_a > "aa") ok
+!(s_a >= "aa") ok
+(s_a <= "aa") ok
+(s_a < "aa") ok
+(cmp(s_aa, s_a) > 0) ok
+!(s_aa == s_a) ok
+(s_aa != s_a) ok
+(s_aa > s_a) ok
+(s_aa >= s_a) ok
+!(s_aa <= s_a) ok
+!(s_aa < s_a) ok
+(cmp("aa", s_a) > 0) ok
+!("aa" == s_a) ok
+("aa" != s_a) ok
+("aa" > s_a) ok
+("aa" >= s_a) ok
+!("aa" <= s_a) ok
+!("aa" < s_a) ok
+(cmp(s_aa, "a") > 0) ok
+!(s_aa == "a") ok
+(s_aa != "a") ok
+(s_aa > "a") ok
+(s_aa >= "a") ok
+!(s_aa <= "a") ok
+!(s_aa < "a") ok
+(cmp(s_a, s_a) == 0) ok
+(s_a == s_a) ok
+!(s_a != s_a) ok
+!(s_a > s_a) ok
+(s_a >= s_a) ok
+(s_a <= s_a) ok
+!(s_a < s_a) ok
+(cmp("a", s_a) == 0) ok
+("a" == s_a) ok
+!("a" != s_a) ok
+!("a" > s_a) ok
+("a" >= s_a) ok
+("a" <= s_a) ok
+!("a" < s_a) ok
+(cmp(s_a, "a") == 0) ok
+(s_a == "a") ok
+!(s_a != "a") ok
+!(s_a > "a") ok
+(s_a >= "a") ok
+(s_a <= "a") ok
+!(s_a < "a") ok
+(cmp(s_aa, s_aa) == 0) ok
+(s_aa == s_aa) ok
+!(s_aa != s_aa) ok
+!(s_aa > s_aa) ok
+(s_aa >= s_aa) ok
+(s_aa <= s_aa) ok
+!(s_aa < s_aa) ok
+(cmp("aa", s_aa) == 0) ok
+("aa" == s_aa) ok
+!("aa" != s_aa) ok
+!("aa" > s_aa) ok
+("aa" >= s_aa) ok
+("aa" <= s_aa) ok
+!("aa" < s_aa) ok
+(cmp(s_aa, "aa") == 0) ok
+(s_aa == "aa") ok
+!(s_aa != "aa") ok
+!(s_aa > "aa") ok
+(s_aa >= "aa") ok
+(s_aa <= "aa") ok
+!(s_aa < "aa") ok
+(cmp(s_a, s_b) < 0) ok
+!(s_a == s_b) ok
+(s_a != s_b) ok
+!(s_a > s_b) ok
+!(s_a >= s_b) ok
+(s_a <= s_b) ok
+(s_a < s_b) ok
+(cmp("a", s_b) < 0) ok
+!("a" == s_b) ok
+("a" != s_b) ok
+!("a" > s_b) ok
+!("a" >= s_b) ok
+("a" <= s_b) ok
+("a" < s_b) ok
+(cmp(s_a, "b") < 0) ok
+!(s_a == "b") ok
+(s_a != "b") ok
+!(s_a > "b") ok
+!(s_a >= "b") ok
+(s_a <= "b") ok
+(s_a < "b") ok
+(cmp(s_b, s_a) > 0) ok
+!(s_b == s_a) ok
+(s_b != s_a) ok
+(s_b > s_a) ok
+(s_b >= s_a) ok
+!(s_b <= s_a) ok
+!(s_b < s_a) ok
+(cmp("b", s_a) > 0) ok
+!("b" == s_a) ok
+("b" != s_a) ok
+("b" > s_a) ok
+("b" >= s_a) ok
+!("b" <= s_a) ok
+!("b" < s_a) ok
+(cmp(s_b, "a") > 0) ok
+!(s_b == "a") ok
+(s_b != "a") ok
+(s_b > "a") ok
+(s_b >= "a") ok
+!(s_b <= "a") ok
+!(s_b < "a") ok
+(cmp(s_a, s_ba) < 0) ok
+!(s_a == s_ba) ok
+(s_a != s_ba) ok
+!(s_a > s_ba) ok
+!(s_a >= s_ba) ok
+(s_a <= s_ba) ok
+(s_a < s_ba) ok
+(cmp("a", s_ba) < 0) ok
+!("a" == s_ba) ok
+("a" != s_ba) ok
+!("a" > s_ba) ok
+!("a" >= s_ba) ok
+("a" <= s_ba) ok
+("a" < s_ba) ok
+(cmp(s_a, "ba") < 0) ok
+!(s_a == "ba") ok
+(s_a != "ba") ok
+!(s_a > "ba") ok
+!(s_a >= "ba") ok
+(s_a <= "ba") ok
+(s_a < "ba") ok
+(cmp(s_ba, s_a) > 0) ok
+!(s_ba == s_a) ok
+(s_ba != s_a) ok
+(s_ba > s_a) ok
+(s_ba >= s_a) ok
+!(s_ba <= s_a) ok
+!(s_ba < s_a) ok
+(cmp("ba", s_a) > 0) ok
+!("ba" == s_a) ok
+("ba" != s_a) ok
+("ba" > s_a) ok
+("ba" >= s_a) ok
+!("ba" <= s_a) ok
+!("ba" < s_a) ok
+(cmp(s_ba, "a") > 0) ok
+!(s_ba == "a") ok
+(s_ba != "a") ok
+(s_ba > "a") ok
+(s_ba >= "a") ok
+!(s_ba <= "a") ok
+!(s_ba < "a") ok
+(cmp(s_aa, s_ab) < 0) ok
+!(s_aa == s_ab) ok
+(s_aa != s_ab) ok
+!(s_aa > s_ab) ok
+!(s_aa >= s_ab) ok
+(s_aa <= s_ab) ok
+(s_aa < s_ab) ok
+(cmp("aa", s_ab) < 0) ok
+!("aa" == s_ab) ok
+("aa" != s_ab) ok
+!("aa" > s_ab) ok
+!("aa" >= s_ab) ok
+("aa" <= s_ab) ok
+("aa" < s_ab) ok
+(cmp(s_aa, "ab") < 0) ok
+!(s_aa == "ab") ok
+(s_aa != "ab") ok
+!(s_aa > "ab") ok
+!(s_aa >= "ab") ok
+(s_aa <= "ab") ok
+(s_aa < "ab") ok
+(cmp(s_ab, s_aa) > 0) ok
+!(s_ab == s_aa) ok
+(s_ab != s_aa) ok
+(s_ab > s_aa) ok
+(s_ab >= s_aa) ok
+!(s_ab <= s_aa) ok
+!(s_ab < s_aa) ok
+(cmp("ab", s_aa) > 0) ok
+!("ab" == s_aa) ok
+("ab" != s_aa) ok
+("ab" > s_aa) ok
+("ab" >= s_aa) ok
+!("ab" <= s_aa) ok
+!("ab" < s_aa) ok
+(cmp(s_ab, "aa") > 0) ok
+!(s_ab == "aa") ok
+(s_ab != "aa") ok
+(s_ab > "aa") ok
+(s_ab >= "aa") ok
+!(s_ab <= "aa") ok
+!(s_ab < "aa") ok
+(cmp(s_ba, s_bb) < 0) ok
+!(s_ba == s_bb) ok
+(s_ba != s_bb) ok
+!(s_ba > s_bb) ok
+!(s_ba >= s_bb) ok
+(s_ba <= s_bb) ok
+(s_ba < s_bb) ok
+(cmp("ba", s_bb) < 0) ok
+!("ba" == s_bb) ok
+("ba" != s_bb) ok
+!("ba" > s_bb) ok
+!("ba" >= s_bb) ok
+("ba" <= s_bb) ok
+("ba" < s_bb) ok
+(cmp(s_ba, "bb") < 0) ok
+!(s_ba == "bb") ok
+(s_ba != "bb") ok
+!(s_ba > "bb") ok
+!(s_ba >= "bb") ok
+(s_ba <= "bb") ok
+(s_ba < "bb") ok
+(cmp(s_bb, s_ba) > 0) ok
+!(s_bb == s_ba) ok
+(s_bb != s_ba) ok
+(s_bb > s_ba) ok
+(s_bb >= s_ba) ok
+!(s_bb <= s_ba) ok
+!(s_bb < s_ba) ok
+(cmp("bb", s_ba) > 0) ok
+!("bb" == s_ba) ok
+("bb" != s_ba) ok
+("bb" > s_ba) ok
+("bb" >= s_ba) ok
+!("bb" <= s_ba) ok
+!("bb" < s_ba) ok
+(cmp(s_bb, "ba") > 0) ok
+!(s_bb == "ba") ok
+(s_bb != "ba") ok
+(s_bb > "ba") ok
+(s_bb >= "ba") ok
+!(s_bb <= "ba") ok
+!(s_bb < "ba") ok
+(cmp(s_aa, s_b) < 0) ok
+!(s_aa == s_b) ok
+(s_aa != s_b) ok
+!(s_aa > s_b) ok
+!(s_aa >= s_b) ok
+(s_aa <= s_b) ok
+(s_aa < s_b) ok
+(cmp("aa", s_b) < 0) ok
+!("aa" == s_b) ok
+("aa" != s_b) ok
+!("aa" > s_b) ok
+!("aa" >= s_b) ok
+("aa" <= s_b) ok
+("aa" < s_b) ok
+(cmp(s_aa, "b") < 0) ok
+!(s_aa == "b") ok
+(s_aa != "b") ok
+!(s_aa > "b") ok
+!(s_aa >= "b") ok
+(s_aa <= "b") ok
+(s_aa < "b") ok
+(cmp(s_b, s_aa) > 0) ok
+!(s_b == s_aa) ok
+(s_b != s_aa) ok
+(s_b > s_aa) ok
+(s_b >= s_aa) ok
+!(s_b <= s_aa) ok
+!(s_b < s_aa) ok
+(cmp("b", s_aa) > 0) ok
+!("b" == s_aa) ok
+("b" != s_aa) ok
+("b" > s_aa) ok
+("b" >= s_aa) ok
+!("b" <= s_aa) ok
+!("b" < s_aa) ok
+(cmp(s_b, "aa") > 0) ok
+!(s_b == "aa") ok
+(s_b != "aa") ok
+(s_b > "aa") ok
+(s_b >= "aa") ok
+!(s_b <= "aa") ok
+!(s_b < "aa") ok
Index: tests/collections/string-compare.cfa
===================================================================
--- tests/collections/string-compare.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
+++ tests/collections/string-compare.cfa	(revision 154672d291edddbe2fa954c43ae7101329e5a6e2)
@@ -0,0 +1,76 @@
+#define chk(X) \
+    printf( #X " %s\n", ((X)?"ok":"WRONG") );
+
+#define test_eq_(l, r) \
+    chk( (cmp(l, r) == 0) ) \
+    chk(  (l == r) ) \
+    chk( !(l != r) ) \
+    chk( !(l >  r) ) \
+    chk(  (l >= r) ) \
+    chk(  (l <= r) ) \
+    chk( !(l <  r) )
+
+#define test_eq(l, r) \
+    test_eq_(s_ ## l, s_ ## r) \
+    test_eq_(    # l, s_ ## r) \
+    test_eq_(s_ ## l,     # r)
+
+#define test_lt_(l, r) \
+    chk( (cmp(l, r) < 0) ) \
+    chk( !(l == r) ) \
+    chk(  (l != r) ) \
+    chk( !(l >  r) ) \
+    chk( !(l >= r) ) \
+    chk(  (l <= r) ) \
+    chk(  (l <  r) )
+
+#define test_gt_(l, r) \
+    chk( (cmp(l, r) > 0) ) \
+    chk( !(l == r) ) \
+    chk(  (l != r) ) \
+    chk(  (l >  r) ) \
+    chk(  (l >= r) ) \
+    chk( !(l <= r) ) \
+    chk( !(l <  r) )
+
+#define test_lt(l, r) \
+    test_lt_(s_ ## l, s_ ## r) \
+    test_lt_(    # l, s_ ## r) \
+    test_lt_(s_ ## l,     # r) \
+    test_gt_(s_ ## r, s_ ## l) \
+    test_gt_(    # r, s_ ## l) \
+    test_gt_(s_ ## r,     # l)
+
+#define define_run(STR_T) \
+    void run_ ## STR_T (void) {    \
+        printf("------- %s -------\n", #STR_T); \
+        STR_T s_   = ""  ;        \
+        STR_T s_a  = "a" ;        \
+        STR_T s_aa = "aa";        \
+        STR_T s_ab = "ab";        \
+        STR_T s_b  = "b" ;        \
+        STR_T s_ba = "ba";        \
+        STR_T s_bb = "bb";        \
+        test_eq(,)                \
+        test_lt(,a)               \
+        test_lt(,aa)              \
+        test_lt(a,aa)             \
+        test_eq(a,a)              \
+        test_eq(aa,aa)            \
+        test_lt(a,b)              \
+        test_lt(a,ba)             \
+        test_lt(aa,ab)            \
+        test_lt(ba,bb)            \
+        test_lt(aa,b)             \
+    }
+
+#include <collections/string.hfa>
+define_run(string)
+
+#include <collections/string_res.hfa>
+define_run(string_res)
+
+int main() {
+    run_string();
+    run_string_res();
+}
