Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/ResolvExpr/AdjustExprType.cc	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -28,4 +28,5 @@
 		void premutate( BasicType * ) { visit_children = false; }
 		void premutate( PointerType * ) { visit_children = false; }
+		void premutate( ArrayType * ) { visit_children = false; }
 		void premutate( FunctionType * ) { visit_children = false; }
 		void premutate( StructInstType * ) { visit_children = false; }
@@ -59,5 +60,4 @@
 
 	Type * AdjustExprType::postmutate( ArrayType * arrayType ) {
-		// need to recursively mutate the base type in order for multi-dimensional arrays to work.
 		PointerType *pointerType = new PointerType( arrayType->get_qualifiers(), arrayType->base );
 		arrayType->base = nullptr;
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -180,9 +180,4 @@
 			throw SemanticError( "No reasonable alternatives for expression ", expr );
 		}
-		for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
-			if ( adjust ) {
-				adjustExprType( i->expr->get_result(), i->env, indexer );
-			}
-		}
 		if ( prune ) {
 			PRINT(
@@ -206,4 +201,10 @@
 				std::cerr << "there are " << alternatives.size() << " alternatives after elimination" << std::endl;
 			)
+		}
+		// adjust types after pruning so that types substituted by pruneAlternatives are correctly adjusted
+		for ( AltList::iterator i = alternatives.begin(); i != alternatives.end(); ++i ) {
+			if ( adjust ) {
+				adjustExprType( i->expr->get_result(), i->env, indexer );
+			}
 		}
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/ResolvExpr/Unify.cc	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -17,5 +17,5 @@
 #include <iterator>               // for back_insert_iterator, back_inserter
 #include <map>                    // for _Rb_tree_const_iterator, _Rb_tree_i...
-#include <memory>                 // for unique_ptr, auto_ptr
+#include <memory>                 // for unique_ptr
 #include <set>                    // for set
 #include <string>                 // for string, operator==, operator!=, bas...
@@ -170,5 +170,5 @@
 				Type *common = 0;
 				// attempt to unify equivalence class type (which has qualifiers stripped, so they must be restored) with the type to bind to
-				std::auto_ptr< Type > newType( curClass.type->clone() );
+				std::unique_ptr< Type > newType( curClass.type->clone() );
 				newType->get_qualifiers() = typeInst->get_qualifiers();
 				if ( unifyInexact( newType.get(), other, env, needAssertions, haveAssertions, openVars, widenMode & WidenMode( curClass.allowWidening, true ), indexer, common ) ) {
@@ -459,9 +459,4 @@
 		if ( otherArray && arrayType->get_isVarLen() == otherArray->get_isVarLen() ) {
 
-			// not positive this is correct in all cases, but it's needed for typedefs
-			if ( arrayType->get_isVarLen() || otherArray->get_isVarLen() ) {
-				return;
-			}
-
 			if ( ! arrayType->get_isVarLen() && ! otherArray->get_isVarLen() &&
 				arrayType->get_dimension() != 0 && otherArray->get_dimension() != 0 ) {
Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/SymTab/FixFunction.cc	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -50,4 +50,5 @@
 
 	void FixFunction::premutate(FunctionDecl *) { visit_children = false; }
+	void FixFunction::premutate(ArrayType *) { visit_children = false; }
 	void FixFunction::premutate(BasicType *) { visit_children = false; }
 	void FixFunction::premutate(PointerType *) { visit_children = false; }
Index: src/SymTab/FixFunction.h
===================================================================
--- src/SymTab/FixFunction.h	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/SymTab/FixFunction.h	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -31,4 +31,5 @@
 		Type * postmutate(ArrayType * arrayType);
 
+		void premutate(ArrayType * arrayType);
 		void premutate(VoidType * voidType);
 		void premutate(BasicType * basicType);
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/SymTab/Validate.cc	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -668,5 +668,4 @@
 		}
 		filter( translationUnit, isTypedef, true );
-
 	}
 
@@ -676,15 +675,15 @@
 		TypedefMap::const_iterator def = typedefNames.find( typeInst->get_name() );
 		if ( def != typedefNames.end() ) {
-			Type *ret = def->second.first->get_base()->clone();
+			Type *ret = def->second.first->base->clone();
 			ret->get_qualifiers() |= typeInst->get_qualifiers();
 			// place instance parameters on the typedef'd type
-			if ( ! typeInst->get_parameters().empty() ) {
+			if ( ! typeInst->parameters.empty() ) {
 				ReferenceToType *rtt = dynamic_cast<ReferenceToType*>(ret);
 				if ( ! rtt ) {
-					throw SemanticError("cannot apply type parameters to base type of " + typeInst->get_name());
+					throw SemanticError("Cannot apply type parameters to base type of " + typeInst->name);
 				}
 				rtt->get_parameters().clear();
-				cloneAll( typeInst->get_parameters(), rtt->get_parameters() );
-				mutateAll( rtt->get_parameters(), *visitor );  // recursively fix typedefs on parameters
+				cloneAll( typeInst->parameters, rtt->parameters );
+				mutateAll( rtt->parameters, *visitor );  // recursively fix typedefs on parameters
 			} // if
 			delete typeInst;
@@ -692,8 +691,22 @@
 		} else {
 			TypeDeclMap::const_iterator base = typedeclNames.find( typeInst->get_name() );
-			assertf( base != typedeclNames.end(), "Cannot find typedecl name %s", typeInst->get_name().c_str() );
+			assertf( base != typedeclNames.end(), "Cannot find typedecl name %s", typeInst->name.c_str() );
 			typeInst->set_baseType( base->second );
 		} // if
 		return typeInst;
+	}
+
+	struct VarLenChecker : WithShortCircuiting {
+		void previsit( FunctionType * ) { visit_children = false; }
+		void previsit( ArrayType * at ) {
+			isVarLen |= at->isVarLen;
+		}
+		bool isVarLen = false;
+	};
+
+	bool isVariableLength( Type * t ) {
+		PassVisitor<VarLenChecker> varLenChecker;
+		maybeAccept( t, varLenChecker );
+		return varLenChecker.pass.isVarLen;
 	}
 
@@ -706,5 +719,9 @@
 			Type * t2 = typedefNames[ tyDecl->get_name() ].first->get_base();
 			if ( ! ResolvExpr::typesCompatible( t1, t2, Indexer() ) ) {
-				throw SemanticError( "cannot redefine typedef: " + tyDecl->get_name() );
+				throw SemanticError( "Cannot redefine typedef: " + tyDecl->name );
+			}
+			// cannot redefine VLA typedefs
+			if ( isVariableLength( t1 ) || isVariableLength( t2 ) ) {
+				throw SemanticError( "Cannot redefine typedef: " + tyDecl->name );
 			}
 		} else {
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/SynTree/Type.h	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -298,5 +298,8 @@
 	void set_isStatic( bool newValue ) { isStatic = newValue; }
 
-	virtual bool isComplete() const override { return ! isVarLen; }
+	// array types are complete if they have a dimension expression or are
+	// VLAs ('*' in parameter declaration), and incomplete otherwise.
+	// See 6.7.6.2
+	virtual bool isComplete() const override { return dimension || isVarLen; }
 
 	virtual ArrayType *clone() const override { return new ArrayType( *this ); }
Index: src/tests/.expect/castError.txt
===================================================================
--- src/tests/.expect/castError.txt	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/tests/.expect/castError.txt	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -4,16 +4,4 @@
 ... to:
   charAlternatives are:
-Cost ( 1, 0, 0, 0 ): Cast of:
-     Variable Expression: f: function
-       accepting unspecified arguments
-     ... returning nothing 
-
-   ... to:
-     char
- (types:
-   char
- )
- Environment: 
-
 Cost ( 1, 0, 0, 0 ): Cast of:
      Variable Expression: f: signed int
@@ -34,3 +22,15 @@
  Environment: 
 
+Cost ( 1, 0, 0, 0 ): Cast of:
+     Variable Expression: f: function
+       accepting unspecified arguments
+     ... returning nothing 
 
+   ... to:
+     char
+ (types:
+   char
+ )
+ Environment: 
+
+
Index: src/tests/.expect/typedefRedef-ERR1.txt
===================================================================
--- src/tests/.expect/typedefRedef-ERR1.txt	(revision b1e68d0353f497191202b2ee47853c063104f360)
+++ src/tests/.expect/typedefRedef-ERR1.txt	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -0,0 +1,2 @@
+typedefRedef.c:4:1 error: Cannot redefine typedef: Foo
+typedefRedef.c:60:1 error: Cannot redefine typedef: ARR
Index: src/tests/Makefile.am
===================================================================
--- src/tests/Makefile.am	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/tests/Makefile.am	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -138,2 +138,5 @@
 completeTypeError : completeTypeError.c @CFA_BINDIR@/@CFA_NAME@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
+
+typedefRedef-ERR1: typedefRedef.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
Index: src/tests/Makefile.in
===================================================================
--- src/tests/Makefile.in	(revision 0dc954bd83db8e34f0ec3ef5aa7213bf36083ab9)
+++ src/tests/Makefile.in	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -892,4 +892,7 @@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
 
+typedefRedef-ERR1: typedefRedef.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
Index: src/tests/typedefRedef.c
===================================================================
--- src/tests/typedefRedef.c	(revision b1e68d0353f497191202b2ee47853c063104f360)
+++ src/tests/typedefRedef.c	(revision b1e68d0353f497191202b2ee47853c063104f360)
@@ -0,0 +1,69 @@
+typedef volatile struct Foo FooInterm;
+typedef const FooInterm Foo;
+#ifdef ERR1
+typedef struct Foo Foo;
+#endif
+
+typedef int ** pt;
+typedef int ** pt;
+
+#ifdef __CFA__
+extern "C" {
+#endif
+typedef int __io_read_fn ( char buf);
+typedef int __io_write_fn ( const char buf);
+
+
+__io_read_fn read;
+__io_write_fn write;
+#ifdef __CFA__
+}
+#endif
+
+int sz;
+typedef int FUNC(int, ...);
+typedef int FUNC(int, ...);
+
+typedef int ARR[];
+typedef int ARR[];
+// #ifdef ERR1
+// if a typedef has an array dimension,
+// it can only be redefined to the same dimension
+typedef int ARR[2];
+// #endif
+
+typedef int X;
+typedef int Y;
+typedef Y Y2;
+typedef X X2;
+
+typedef Y2 Z;
+typedef X2 Z;
+
+typedef Z X2;
+typedef int X2;
+typedef Z X2;
+typedef int X2;
+
+// xxx - this doesn't work yet due to parsing problems with generic types
+// #ifdef __CFA__
+// typedef forall(type T) void foo(T);
+// typedef forall(type T) void foo(T);
+// typedef forall(type S) void foo(S); // should be allowed to do this...
+// #endif
+
+int main() {
+  typedef int ARR[sz];
+
+  // can't redefine typedef which is VLA
+#if ERR1
+  typedef int ARR[sz];
+#endif
+
+  Foo *x;
+
+  typedef struct Bar Foo;
+  Foo *y;
+
+  typedef int *** pt;
+}
