int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
{
	int rc = SEPOL_ERR;
	struct cil_args_resolve extra_args;
	enum cil_pass pass = CIL_PASS_TIF;
	uint32_t changed = 0;

	if (db == NULL || current == NULL) {
		return rc;
	}

	extra_args.db = db;
	extra_args.pass = pass;
	extra_args.changed = &changed;
	extra_args.block = NULL;
	extra_args.macro = NULL;
	extra_args.optional = NULL;
	extra_args.boolif= NULL;
	extra_args.sidorder_lists = NULL;
	extra_args.classorder_lists = NULL;
	extra_args.unordered_classorder_lists = NULL;
	extra_args.catorder_lists = NULL;
	extra_args.sensitivityorder_lists = NULL;
	extra_args.in_list = NULL;

	cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
	cil_list_init(&extra_args.sidorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.classorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.unordered_classorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.catorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.sensitivityorder_lists, CIL_LIST_ITEM);
	cil_list_init(&extra_args.in_list, CIL_IN);
	for (pass = CIL_PASS_TIF; pass < CIL_PASS_NUM; pass++) {
		extra_args.pass = pass;
		rc = cil_tree_walk(current, __cil_resolve_ast_node_helper, __cil_resolve_ast_first_child_helper, __cil_resolve_ast_last_child_helper, &extra_args);
		if (rc != SEPOL_OK) {
			cil_log(CIL_INFO, "Pass %i of resolution failed\n", pass);
			goto exit;
		}

		if (pass == CIL_PASS_IN) {
			rc = cil_resolve_in_list(&extra_args);
			if (rc != SEPOL_OK) {
				goto exit;
			}
			cil_list_destroy(&extra_args.in_list, CIL_FALSE);
		}

		if (pass == CIL_PASS_MISC1) {
			db->sidorder = __cil_ordered_lists_merge_all(&extra_args.sidorder_lists, NULL);
			if (db->sidorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			db->classorder = __cil_ordered_lists_merge_all(&extra_args.classorder_lists, &extra_args.unordered_classorder_lists);
			if (db->classorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			db->catorder = __cil_ordered_lists_merge_all(&extra_args.catorder_lists, NULL);
			if (db->catorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}
			cil_set_cat_values(db->catorder, db);
			db->sensitivityorder = __cil_ordered_lists_merge_all(&extra_args.sensitivityorder_lists, NULL);
			if (db->sensitivityorder == NULL) {
				rc = SEPOL_ERR;
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_SID);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_CLASS);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_CAT);
			if (rc != SEPOL_OK) {
				goto exit;
			}

			rc = __cil_verify_ordered(current, CIL_SENS);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}

		if (changed && (pass > CIL_PASS_CALL1)) {
			struct cil_list_item *item;
			/* Need to re-resolve because an optional was disabled that contained
			 * one or more declarations. We only need to reset to the call1 pass 
			 * because things done in the preceding passes aren't allowed in 
			 * optionals, and thus can't be disabled.
			 * Note: set pass to CIL_PASS_CALL1 because the pass++ will increment 
			 * it to CIL_PASS_CALL2
			 */
			cil_log(CIL_INFO, "Resetting declarations\n");

			if (pass >= CIL_PASS_MISC1) {
				__cil_ordered_lists_reset(&extra_args.sidorder_lists);
				__cil_ordered_lists_reset(&extra_args.classorder_lists);
				__cil_ordered_lists_reset(&extra_args.unordered_classorder_lists);
				__cil_ordered_lists_reset(&extra_args.catorder_lists);
				__cil_ordered_lists_reset(&extra_args.sensitivityorder_lists);
				cil_list_destroy(&db->sidorder, CIL_FALSE);
				cil_list_destroy(&db->classorder, CIL_FALSE);
				cil_list_destroy(&db->catorder, CIL_FALSE);
				cil_list_destroy(&db->sensitivityorder, CIL_FALSE);
			}

			pass = CIL_PASS_CALL1;

			rc = cil_reset_ast(current);
			if (rc != SEPOL_OK) {
				cil_log(CIL_ERR, "Failed to reset declarations\n");
				goto exit;
			}
			cil_list_for_each(item, extra_args.disabled_optionals) {
				cil_tree_children_destroy(item->data);
			}
			cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
			cil_list_init(&extra_args.disabled_optionals, CIL_NODE);
			changed = 0;
		}
	}

	rc = __cil_verify_initsids(db->sidorder);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = SEPOL_OK;
exit:
	__cil_ordered_lists_destroy(&extra_args.sidorder_lists);
	__cil_ordered_lists_destroy(&extra_args.classorder_lists);
	__cil_ordered_lists_destroy(&extra_args.catorder_lists);
	__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
	__cil_ordered_lists_destroy(&extra_args.unordered_classorder_lists);
	cil_list_destroy(&extra_args.disabled_optionals, CIL_FALSE);
	cil_list_destroy(&extra_args.in_list, CIL_FALSE);

	return rc;
}