Merge branch 'when-stmt' into devel

Conflicts:
	src/resolve.c
	src/tree_data.c
	tests/CMakeLists.txt
diff --git a/src/resolve.c b/src/resolve.c
index 72874fb..52edf57 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -2142,18 +2142,17 @@
  * @param[in] type Type definition to use.
  * @param[in] value Default value to check.
  * @param[in] module Type module.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-check_default(struct lys_type *type, const char *value, struct lys_module *module, int first, uint32_t line)
+check_default(struct lys_type *type, const char *value, struct lys_module *module)
 {
     struct lyd_node_leaf_list node;
     int ret = EXIT_SUCCESS;
 
     /* dummy leaf */
+    memset(&node, 0, sizeof node);
     node.value_str = value;
     node.value_type = type->base;
     node.schema = calloc(1, sizeof (struct lys_node_leaf));
@@ -2174,13 +2173,13 @@
             ret = EXIT_FAILURE;
             goto finish;
         }
-        ret = check_default(&type->info.lref.target->type, value, module, first, line);
+        ret = check_default(&type->info.lref.target->type, value, module);
 
     } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
         /* it was converted to JSON format before, nothing else sensible we can do */
 
     } else {
-        ret = lyp_parse_value(&node, NULL, 1, NULL, line);
+        ret = lyp_parse_value(&node, NULL, 1);
     }
 
 finish:
@@ -2202,12 +2201,11 @@
  * @param[in] index Index of the key in the key list.
  * @param[in] name The name of the keys.
  * @param[in] len The name length.
- * @param[in] line The line in the input file.
  *
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-check_key(struct lys_node_list *list, int index, const char *name, int len, uint32_t line)
+check_key(struct lys_node_list *list, int index, const char *name, int len)
 {
     struct lys_node_leaf *key = list->keys[index];
     char *dup = NULL;
@@ -2224,7 +2222,7 @@
             dup[len] = '\0';
             name = dup;
         }
-        LOGVAL(LYE_KEY_MISS, line, LY_VLOG_LYS, list, name);
+        LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
         free(dup);
         return -1;
     }
@@ -2232,33 +2230,40 @@
     /* uniqueness */
     for (j = index - 1; j >= 0; j--) {
         if (key == list->keys[j]) {
-            LOGVAL(LYE_KEY_DUP, line, LY_VLOG_LYS, list, key->name);
+            LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
             return -1;
         }
     }
 
     /* key is a leaf */
     if (key->nodetype != LYS_LEAF) {
-        LOGVAL(LYE_KEY_NLEAF, line, LY_VLOG_LYS, list, key->name);
+        LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
         return -1;
     }
 
     /* type of the leaf is not built-in empty */
     if (key->type.base == LY_TYPE_EMPTY) {
-        LOGVAL(LYE_KEY_TYPE, line, LY_VLOG_LYS, list, key->name);
+        LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
         return -1;
     }
 
     /* config attribute is the same as of the list */
     if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
-        LOGVAL(LYE_KEY_CONFIG, line, LY_VLOG_LYS, list, key->name);
+        LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
         return -1;
     }
 
     /* key is not placed from augment */
     if (key->parent->nodetype == LYS_AUGMENT) {
-        LOGVAL(LYE_KEY_MISS, line, 0, NULL, key->name);
-        LOGVAL(LYE_SPEC, 0, LY_VLOG_LYS, key, "Key inserted from augment.");
+        LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
+        LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
+        return -1;
+    }
+
+    /* key is not when-conditional */
+    if (key->when) {
+        LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
+        LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
         return -1;
     }
 
@@ -2270,13 +2275,11 @@
  *
  * @param[in] parent The parent node of the unique structure.
  * @param[in] uniq_str_path One path from the unique string.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line The line in the input file.
  *
  * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
  */
 int
-resolve_unique(struct lys_node *parent, const char *uniq_str_path, int first, uint32_t line)
+resolve_unique(struct lys_node *parent, const char *uniq_str_path)
 {
     int rc;
     const struct lys_node *leaf = NULL;
@@ -2284,30 +2287,27 @@
     rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf);
     if (rc || !leaf) {
         if (rc) {
-            LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
+            LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
             if (rc > 0) {
-                LOGVAL(LYE_INCHAR, 0, 0, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
+                LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
             }
             rc = -1;
-        } else if (!first) {
-            LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
-            LOGVAL(LYE_SPEC, 0, 0, NULL, "Target leaf not found.");
-            rc = -1;
         } else {
+            LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
+            LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
             rc = EXIT_FAILURE;
         }
         goto error;
     }
     if (leaf->nodetype != LYS_LEAF) {
-        LOGVAL(LYE_INARG, line, LY_VLOG_LYS, parent, uniq_str_path, "unique");
-        LOGVAL(LYE_SPEC, 0, 0, NULL, "Target is not a leaf.");
+        LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
+        LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
         rc = -1;
         goto error;
     }
 
     /* check status */
-    if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name,
-                         line, leaf)) {
+    if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
         return -1;
     }
 
@@ -2326,14 +2326,12 @@
  *
  * @param[in] name Feature name.
  * @param[in] module Module to search in.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line The line in the input file.
  * @param[out] ret Pointer to the resolved feature. Can be NULL.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_feature(const char *id, const struct lys_module *module, int first, uint32_t line, struct lys_feature **ret)
+resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
 {
     const char *mod_name, *name;
     int mod_name_len, nam_len, i, j;
@@ -2344,14 +2342,14 @@
 
     /* check prefix */
     if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
-        LOGVAL(LYE_INCHAR, line, 0, NULL, id[-i], &id[-i]);
+        LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
         return -1;
     }
 
     module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
     if (!module) {
         /* identity refers unknown data model */
-        LOGVAL(LYE_INMOD_LEN, line, 0, NULL, mod_name_len, mod_name);
+        LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
         return -1;
     }
 
@@ -2362,7 +2360,7 @@
                 /* check status */
                 node = (struct lys_node *)*ret;
                 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
-                                 module->features[j].module, module->features[j].name, line, node)) {
+                                 module->features[j].module, module->features[j].name, node)) {
                     return -1;
                 }
                 *ret = &module->features[j];
@@ -2384,7 +2382,7 @@
                     if (lyp_check_status(node->flags, node->module, node->name,
                                      module->inc[i].submodule->features[j].flags,
                                      module->inc[i].submodule->features[j].module,
-                                     module->inc[i].submodule->features[j].name, line, node)) {
+                                     module->inc[i].submodule->features[j].name, node)) {
                         return -1;
                     }
                     *ret = &(module->inc[i].submodule->features[j]);
@@ -2395,13 +2393,10 @@
     }
 
     /* not found */
-    if (!first) {
-        LOGVAL(LYE_INRESOLV, line, 0, NULL, "feature", id);
-    }
+    LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
     return EXIT_FAILURE;
 }
 
-/* ignores line */
 static void
 unres_data_del(struct unres_data *unres, uint32_t i)
 {
@@ -2532,12 +2527,9 @@
 
 /**
  * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
- *        only specific errors, general no-resolvent error is left to the caller,
- *        but line fail is always displayed.
+ *        only specific errors, general no-resolvent error is left to the caller.
  *
  * @param[in] pred Predicate to use.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  * @param[in] node Node from which the predicate is being resolved
  * @param[in,out] node_match Nodes satisfying the restriction
  *                           without the predicate. Nodes not
@@ -2547,8 +2539,8 @@
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_path_predicate_data(const char *pred, int first, uint32_t line,struct lyd_node *node,
-                            struct unres_data *node_match, int *parsed)
+resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
+                            int *parsed)
 {
     /* ... /node[source = destination] ... */
     struct unres_data source_match, dest_match;
@@ -2573,7 +2565,7 @@
     do {
         if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
                                       &pke_len, &has_predicate)) < 1) {
-            LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
             rc = -1;
             goto error;
         }
@@ -2587,10 +2579,6 @@
             /* must be leaf (key of a list) */
             if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
                     &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
-                /* general error, the one written later will suffice */
-                if ((rc == -1) || !first) {
-                    LOGVAL(LYE_LINE, line, 0, NULL);
-                }
                 i = 0;
                 goto error;
             }
@@ -2600,7 +2588,7 @@
             dest_parent_times = 0;
             if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                             &dest_parent_times)) < 1) {
-                LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
+                LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
                 rc = -1;
                 goto error;
             }
@@ -2608,10 +2596,6 @@
             for (i = 0; i < dest_parent_times; ++i) {
                 dest_match.node[0] = dest_match.node[0]->parent;
                 if (!dest_match.node[0]) {
-                    /* general error, the one written later will suffice */
-                    if (!first) {
-                        LOGVAL(LYE_LINE, line, 0, NULL);
-                    }
                     i = 0;
                     rc = EXIT_FAILURE;
                     goto error;
@@ -2620,10 +2604,6 @@
             while (1) {
                 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
                         &dest_match)) || (dest_match.count != 1)) {
-                    /* general error, the one written later will suffice */
-                    if ((rc == -1) || !first) {
-                        LOGVAL(LYE_LINE, line, 0, NULL);
-                    }
                     i = 0;
                     goto error;
                 }
@@ -2633,7 +2613,7 @@
                 }
                 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                              &dest_parent_times)) < 1) {
-                    LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
+                    LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
                     rc = -1;
                     goto error;
                 }
@@ -2687,14 +2667,12 @@
  *
  * @param[in] node Leafref data node.
  * @param[in] path Path of the leafref.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
- * @param[out] ret Matching nodes. Expects an empty, but allocated structure. Lines left untouched.
+ * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
  */
 static int
-resolve_path_arg_data(struct lyd_node *node, const char *path, int first, uint32_t line, struct unres_data *ret)
+resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
 {
     struct lyd_node *data = NULL;
     const char *prefix, *name;
@@ -2709,7 +2687,7 @@
     /* searching for nodeset */
     do {
         if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
-            LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, path[-i], &path[-i]);
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
             rc = -1;
             goto error;
         }
@@ -2730,7 +2708,7 @@
                 /* relative path */
                 if (!ret->count) {
                     /* error, too many .. */
-                    LOGVAL(LYE_INVAL, line, LY_VLOG_LYD, node, path, node->schema->name);
+                    LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
                     rc = -1;
                     goto error;
                 } else if (!ret->node[0]) {
@@ -2759,8 +2737,8 @@
 
         /* node identifier */
         if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
-            if ((rc == -1) || !first) {
-                LOGVAL(LYE_INELEM_LEN, line, LY_VLOG_LYD, node, nam_len, name);
+            if (rc == -1) {
+                LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
             }
             goto error;
         }
@@ -2778,10 +2756,9 @@
                 /* does not fulfill conditions, remove leafref record */
                 unres_data_del(ret, j);
             }
-            if ((rc = resolve_path_predicate_data(path, first, line, node, ret, &i))) {
-                /* line was already displayed */
-                if ((rc == -1) || !first) {
-                    LOGVAL(LYE_NORESOLV, 0, LY_VLOG_LYD, node, path);
+            if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
+                if (rc == -1) {
+                    LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path);
                 }
                 goto error;
             }
@@ -2789,9 +2766,7 @@
             parsed += i;
 
             if (!ret->count) {
-                if (!first) {
-                    LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, node, path-parsed);
-                }
+                LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path-parsed);
                 rc = EXIT_FAILURE;
                 goto error;
             }
@@ -2815,8 +2790,6 @@
  * @param[in] path Path to use.
  * @param[in] context_node Predicate context node (where the predicate is placed).
  * @param[in] parent Path context node (where the path begins/is placed).
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  *
  * @return 0 on forward reference, otherwise the number
  *         of characters successfully parsed,
@@ -2824,7 +2797,7 @@
  */
 static int
 resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
-                              struct lys_node *parent, int first, uint32_t line)
+                              struct lys_node *parent)
 {
     const struct lys_node *src_node, *dst_node;
     const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
@@ -2834,7 +2807,7 @@
     do {
         if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
                                       &pke_len, &has_predicate)) < 1) {
-            LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path[-i], path-i);
+            LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
             return -parsed+i;
         }
         parsed += i;
@@ -2847,8 +2820,8 @@
         rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
                              LYS_LEAF | LYS_AUGMENT, &src_node);
         if (rc) {
-            if ((rc == -1) || !first) {
-                LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
+            if (rc == -1) {
+                LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
             }
             return 0;
         }
@@ -2856,7 +2829,7 @@
         /* destination */
         if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                      &dest_parent_times)) < 1) {
-            LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr[-i], path_key_expr-i);
+            LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr[-i], path_key_expr-i);
             return -parsed;
         }
         pke_parsed += i;
@@ -2864,7 +2837,7 @@
         /* parent is actually the parent of this leaf, so skip the first ".." */
         for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
             if (!dst_node) {
-                LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
+                LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
                 return 0;
             }
             dst_node = dst_node->parent;
@@ -2876,8 +2849,8 @@
             rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
                                  LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
             if (rc) {
-                if ((rc == -1) || !first) {
-                    LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path_key_expr);
+                if (rc == -1) {
+                    LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
                 }
                 return 0;
             }
@@ -2888,7 +2861,7 @@
 
             if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
                                          &dest_parent_times)) < 1) {
-                LOGVAL(LYE_INCHAR, line, parent ? LY_VLOG_LYS : 0, parent,
+                LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
                        (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
                 return -parsed;
             }
@@ -2897,8 +2870,9 @@
 
         /* check source - dest match */
         if (dst_node->nodetype != LYS_LEAF) {
-            LOGVAL(LYE_NORESOLV, line, parent ? LY_VLOG_LYS : 0, parent, path-parsed);
-            LOGVAL(LYE_SPEC, 0, 0, NULL, "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
+            LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
+            LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
+                   "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
             return -parsed;
         }
     } while (has_predicate);
@@ -2913,14 +2887,12 @@
  * @param[in] parent_node Parent of the leafref.
  * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
  *            has to contain absolute path
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  * @param[out] ret Pointer to the resolved schema node. Can be NULL.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf, int first, uint32_t line,
+resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
                         const struct lys_node **ret)
 {
     const struct lys_node *node;
@@ -2935,7 +2907,7 @@
 
     do {
         if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
-            LOGVAL(LYE_INCHAR, line, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
+            LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
             return -1;
         }
         id += i;
@@ -2947,16 +2919,14 @@
                 /* get start node */
                 node = mod ? mod->data : NULL;
                 if (!node) {
-                    if (!first) {
-                        LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
-                    }
+                    LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
                     return EXIT_FAILURE;
                 }
             } else if (parent_times > 0) {
                 /* node is the parent already, skip one ".." */
                 if (parent_tpdf) {
                     /* the path is not allowed to contain relative path since we are in top level typedef */
-                    LOGVAL(LYE_NORESOLV, line, 0, NULL, path);
+                    LOGVAL(LYE_NORESOLV, 0, NULL, path);
                     return -1;
                 }
 
@@ -2964,9 +2934,7 @@
                 i = 0;
                 while (1) {
                     if (!node) {
-                        if (!first) {
-                            LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
-                        }
+                        LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
                         return EXIT_FAILURE;
                     }
 
@@ -2995,7 +2963,7 @@
         } else {
             /* move down the tree, if possible */
             if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
-                LOGVAL(LYE_INCHAR, line, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
+                LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
                 return -1;
             }
             node = node->child;
@@ -3007,8 +2975,8 @@
 
         rc = lys_get_sibling(node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
         if (rc) {
-            if ((rc == -1) || !first) {
-                LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
+            if (rc == -1) {
+                LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
             }
             return rc;
         }
@@ -3016,11 +2984,11 @@
         if (has_predicate) {
             /* we have predicate, so the current result must be list */
             if (node->nodetype != LYS_LIST) {
-                LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
+                LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
                 return -1;
             }
 
-            i = resolve_path_predicate_schema(id, node, parent, first, line);
+            i = resolve_path_predicate_schema(id, node, parent);
             if (!i) {
                 return EXIT_FAILURE;
             } else if (i < 0) {
@@ -3032,13 +3000,13 @@
 
     /* the target must be leaf or leaf-list */
     if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
-        LOGVAL(LYE_NORESOLV, line, parent_tpdf ? 0 : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
+        LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
         return -1;
     }
 
     /* check status */
     if (lyp_check_status(parent->flags, parent->module, parent->name,
-                     node->flags, node->module, node->name, line, node)) {
+                     node->flags, node->module, node->name, node)) {
         return -1;
     }
 
@@ -3150,12 +3118,11 @@
  *
  * @param[in] data Data node where the path is used
  * @param[in] path Instance-identifier node value.
- * @param[in] line Source line for error messages.
  *
  * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
  */
 static struct lyd_node *
-resolve_instid(struct lyd_node *data, const char *path, int line)
+resolve_instid(struct lyd_node *data, const char *path)
 {
     int i = 0, j;
     struct lyd_node *result = NULL;
@@ -3180,7 +3147,7 @@
     while (path[i]) {
         j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
         if (j <= 0) {
-            LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
             goto error;
         }
         i += j;
@@ -3220,7 +3187,7 @@
 
             j = resolve_predicate(&path[i], &node_match);
             if (j < 1) {
-                LOGVAL(LYE_INPRED, line, LY_VLOG_LYD, data, &path[i-j]);
+                LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
                 goto error;
             }
             i += j;
@@ -3237,7 +3204,7 @@
         return NULL;
     } else if (node_match.count > 1) {
         /* instance identifier must resolve to a single node */
-        LOGVAL(LYE_TOOMANY, line, LY_VLOG_LYD, data, path, "data tree");
+        LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
 
         /* cleanup */
         free(node_match.node);
@@ -3278,13 +3245,11 @@
  *
  * @param[in] aug Augment to use.
  * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
- * @param[in] first Whether this is the first resolution try.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, int first, uint32_t line)
+resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
 {
     int rc;
     struct lys_node *sub;
@@ -3297,13 +3262,11 @@
         return -1;
     }
     if (rc > 0) {
-        LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
+        LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
         return -1;
     }
     if (!aug->target) {
-        if (!first) {
-            LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, aug, "augment", aug->target_name);
-        }
+        LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
         return EXIT_FAILURE;
     }
 
@@ -3318,8 +3281,8 @@
      */
     if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
             && lyp_check_mandatory((struct lys_node *)aug)) {
-        LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, "mandatory", "augment node");
-        LOGVAL(LYE_SPEC, 0, 0, NULL, "When augmenting data in another module, mandatory nodes are not allowed.");
+        LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
+        LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "When augmenting data in another module, mandatory nodes are not allowed.");
         return -1;
     }
 
@@ -3327,8 +3290,8 @@
     if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
         LY_TREE_FOR(aug->child, sub) {
             if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
-                LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
-                LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
+                LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
                        strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
                 return -1;
             }
@@ -3336,15 +3299,15 @@
     } else if (aug->target->nodetype == LYS_CHOICE) {
         LY_TREE_FOR(aug->child, sub) {
             if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
-                LOGVAL(LYE_INCHILDSTMT, line, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
-                LOGVAL(LYE_SPEC, 0, 0, NULL, "Cannot augment \"%s\" with a \"%s\".",
+                LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
+                LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
                        strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
                 return -1;
             }
         }
     } else {
-        LOGVAL(LYE_INARG, line, LY_VLOG_LYS, aug, aug->target_name, "target-node");
-        LOGVAL(LYE_SPEC, 0, 0, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
+        LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
+        LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
         return -1;
     }
 
@@ -3380,12 +3343,11 @@
  *
  * @param[in] uses Uses to use.
  * @param[in,out] unres List of unresolved items.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 static int
-resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres, uint32_t line)
+resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
 {
     struct ly_ctx *ctx;
     struct lys_node *node = NULL;
@@ -3403,8 +3365,8 @@
     LY_TREE_FOR(uses->grp->child, node_aux) {
         node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
         if (!node) {
-            LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, uses->grp->name, "uses");
-            LOGVAL(LYE_SPEC, 0, 0, NULL, "Copying data from grouping failed.");
+            LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
+            LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
             return -1;
         }
     }
@@ -3418,13 +3380,13 @@
         rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
                                               (const struct lys_node **)&node);
         if (rc || !node) {
-            LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
+            LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
             return -1;
         }
 
         if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
-            LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->target_name, "refine");
-            LOGVAL(LYE_SPEC, 0, 0, NULL, "Refine substatements not applicable to the target-node.");
+            LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
+            LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
             return -1;
         }
 
@@ -3457,7 +3419,7 @@
                 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
                                                           (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
                 if (rc || !((struct lys_node_choice *)node)->dflt) {
-                    LOGVAL(LYE_INARG, line, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
+                    LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
                     return -1;
                 }
             }
@@ -3547,7 +3509,7 @@
 
     /* apply augments */
     for (i = 0; i < uses->augment_size; i++) {
-        rc = resolve_augment(&uses->augment[i], uses->child, 0, line);
+        rc = resolve_augment(&uses->augment[i], uses->child);
         if (rc) {
             return -1;
         }
@@ -3614,8 +3576,8 @@
         /* check for circular reference */
         for (base_iter = base; base_iter; base_iter = base_iter->base) {
             if (ident == base_iter) {
-                LOGVAL(LYE_INARG, 0, LY_VLOG_NONE, NULL, base_iter->name, "base");
-                LOGVAL(LYE_SPEC, 0, 0, NULL, "Circular reference of \"%s\" identity.", basename);
+                LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
+                LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
                 return EXIT_FAILURE;
             }
         }
@@ -3654,15 +3616,13 @@
  * @param[in] ident Identity to use.
  * @param[in] basename Base name of the identity.
  * @param[in] parent Either "type" or "identity".
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
 resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
-                   int first, uint32_t line, struct lys_type *type)
+                   struct lys_type *type)
 {
     const char *name;
     int i, mod_name_len = 0;
@@ -3703,7 +3663,7 @@
     module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
     if (!module) {
         /* identity refers unknown data model */
-        LOGVAL(LYE_INMOD, line, 0, NULL, basename);
+        LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
         return -1;
     }
 
@@ -3711,7 +3671,6 @@
     if (!resolve_base_ident_sub(module, ident, name, ret)) {
         goto success;
     } else if (ly_errno) {
-        LOGVAL(LYE_LINE, line, 0, NULL);
         return EXIT_FAILURE;
     }
     /* and all its submodules */
@@ -3719,20 +3678,17 @@
         if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
             goto success;
         } else if (ly_errno) {
-            LOGVAL(LYE_LINE, line, 0, NULL);
             return EXIT_FAILURE;
         }
     }
 
-    if (!first) {
-        LOGVAL(LYE_INARG, line, 0, NULL, basename, parent);
-    }
+    LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, parent);
     return EXIT_FAILURE;
 
 success:
     /* check status */
-    if (lyp_check_status(flags, mod, ident ? ident->name : "of type", (*ret)->flags, (*ret)->module, (*ret)->name,
-                         line, NULL)) {
+    if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
+                         (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
         return -1;
     }
 
@@ -3744,13 +3700,12 @@
  *
  * @param[in] base Base identity.
  * @param[in] ident_name Identityref name.
- * @param[in] line Line from the input file.
  * @param[in] node Node where the identityref is being resolved
  *
  * @return Pointer to the identity resolvent, NULL on error.
  */
 struct lys_ident *
-resolve_identref(struct lys_ident *base, const char *ident_name, uint32_t line, struct lyd_node *node)
+resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
 {
     const char *mod_name, *name;
     int mod_name_len, rc;
@@ -3761,8 +3716,11 @@
     }
 
     rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
-    if (rc < (signed)strlen(ident_name)) {
-        LOGVAL(LYE_INCHAR, line, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
+    if (rc < 1) {
+        LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
+        return NULL;
+    } else if (rc < (signed)strlen(ident_name)) {
+        LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
         return NULL;
     }
 
@@ -3780,7 +3738,7 @@
         }
     }
 
-    LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYD, node, "identityref", ident_name);
+    LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
     return NULL;
 }
 
@@ -3819,67 +3777,72 @@
  *
  * @param[in] uses Uses to use.
  * @param[in] unres Specific unres item.
- * @param[in] first Whether this is the first resolution try.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres, int first, uint32_t line)
+resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
 {
     int rc;
-    struct lys_node *parent;
+    struct lys_node *par_grp;
 
-    /* HACK change unres uses count if it's in a grouping (nacm field used for it) */
-    for (parent = uses->parent; parent && (parent->nodetype != LYS_GROUPING); parent = parent->parent);
+    /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
+     *       is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
+     *       is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
+     *       value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
+     *       LYS_USESGRP flag is used. */
+    for (par_grp = uses->parent; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = par_grp->parent);
 
     if (!uses->grp) {
         rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
         if (rc == -1) {
-            LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, uses, "grouping", uses->name);
+            LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
             return -1;
         } else if (rc > 0) {
-            LOGVAL(LYE_INCHAR, line, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
+            LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
             return -1;
         } else if (!uses->grp) {
-            if (parent && first) {
-                ++parent->nacm;
+            if (par_grp && !(uses->flags & LYS_USESGRP)) {
+                par_grp->nacm++;
+                uses->flags |= LYS_USESGRP;
             }
             return EXIT_FAILURE;
         }
     }
 
     if (uses->grp->nacm) {
-        if (parent && first) {
-            ++parent->nacm;
+        if (par_grp && !(uses->flags & LYS_USESGRP)) {
+            par_grp->nacm++;
+            uses->flags |= LYS_USESGRP;
         }
         return EXIT_FAILURE;
     }
 
-    rc = resolve_uses(uses, unres, line);
+    rc = resolve_uses(uses, unres);
     if (!rc) {
         /* decrease unres count only if not first try */
-        if (parent && !first) {
-            if (!parent->nacm) {
+        if (par_grp && (uses->flags & LYS_USESGRP)) {
+            if (!par_grp->nacm) {
                 LOGINT;
                 return -1;
             }
-            --parent->nacm;
+            par_grp->nacm--;
+            uses->flags &= ~LYS_USESGRP;
         }
 
         /* check status */
         if (lyp_check_status(uses->flags, uses->module, "of uses",
                          uses->grp->flags, uses->grp->module, uses->grp->name,
-                         line, (struct lys_node *)uses)) {
+                         (struct lys_node *)uses)) {
             return -1;
         }
 
         return EXIT_SUCCESS;
+    } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
+        par_grp->nacm++;
+        uses->flags |= LYS_USESGRP;
     }
 
-    if (parent && first && (rc == EXIT_FAILURE)) {
-        ++parent->nacm;
-    }
     return rc;
 }
 
@@ -3888,13 +3851,11 @@
  *
  * @param[in] list List to use.
  * @param[in] keys_str Keys node value.
- * @param[in] first Whether this is the first resolution try. Affects logging.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
-resolve_list_keys(struct lys_node_list *list, const char *keys_str, int first, uint32_t line)
+resolve_list_keys(struct lys_node_list *list, const char *keys_str)
 {
     int i, len, rc;
     const char *value;
@@ -3912,21 +3873,21 @@
 
         rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
         if (rc) {
-            if ((rc == -1) || !first) {
-                LOGVAL(LYE_INRESOLV, line, LY_VLOG_LYS, list, "list keys", keys_str);
+            if (rc == -1) {
+                LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
             }
             return rc;
         }
 
-        if (check_key(list, i, keys_str, len, line)) {
+        if (check_key(list, i, keys_str, len)) {
             /* check_key logs */
             return -1;
         }
 
         /* check status */
         if (lyp_check_status(list->flags, list->module, list->name,
-                         list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
-                         line, (struct lys_node *)list->keys[i])) {
+                             list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
+                             (struct lys_node *)list->keys[i])) {
             return -1;
         }
 
@@ -3945,13 +3906,11 @@
  * Logs directly.
  *
  * @param[in] node Data node with optional must statements.
- * @param[in] first Whether this is the first resolution to try.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
  */
 static int
-resolve_must(struct lyd_node *node, int first, uint32_t line)
+resolve_must(struct lyd_node *node)
 {
     uint8_t i, must_size;
     struct lys_restr *must;
@@ -3987,16 +3946,14 @@
     }
 
     for (i = 0; i < must_size; ++i) {
-        if (lyxp_eval(must[i].expr, node, &set, 1, line)) {
+        if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
             return -1;
         }
 
-        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
+        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
 
         if (!set.value.bool) {
-            if (!first) {
-                LOGVAL(LYE_NOCOND, line, LY_VLOG_LYD, node, "Must", must[i].expr);
-            }
+            LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "Must", must[i].expr);
             return 1;
         }
     }
@@ -4049,38 +4006,95 @@
     return node;
 }
 
+int
+resolve_applies_must(const struct lyd_node *node)
+{
+    switch (node->schema->nodetype) {
+    case LYS_CONTAINER:
+        return ((struct lys_node_container *)node->schema)->must_size;
+    case LYS_LEAF:
+        return ((struct lys_node_leaf *)node->schema)->must_size;
+    case LYS_LEAFLIST:
+        return ((struct lys_node_leaflist *)node->schema)->must_size;
+    case LYS_LIST:
+        return ((struct lys_node_list *)node->schema)->must_size;
+    case LYS_ANYXML:
+        return ((struct lys_node_anyxml *)node->schema)->must_size;
+    default:
+        return 0;
+    }
+}
+
+int
+resolve_applies_when(const struct lyd_node *node)
+{
+    struct lys_node *parent;
+
+    assert(node);
+
+    if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
+        return 1;
+    }
+
+    parent = node->schema;
+    goto check_augment;
+
+    while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
+        if (((struct lys_node_uses *)parent)->when) {
+            return 1;
+        }
+check_augment:
+
+        if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
+                (((struct lys_node_augment *)parent->parent)->when))) {
+
+        }
+        parent = lys_parent(parent);
+    }
+
+    return 0;
+}
+
 /**
  * @brief Resolve (check) all when conditions relevant for \p node.
  * Logs directly.
  *
  * @param[in] node Data node, whose conditional reference, if such, is being decided.
- * @param[in] first Whether this is the first resolution to try.
- * @param[in] line Line in the input file.
  *
- * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
+ * @return
+ *  -1 - error, ly_errno is set
+ *   0 - true "when" statement
+ *   0, ly_vecode = LYVE_NOCOND - false "when" statement
+ *   1, ly_vecode = LYVE_INWHEN - nodes needed to resolve are conditional and not yet resolved (under another "when")
  */
 static int
-resolve_when(struct lyd_node *node, int first, uint32_t line)
+resolve_when(struct lyd_node *node)
 {
     struct lyd_node *ctx_node = NULL;
     struct lys_node *parent;
     struct lyxp_set set;
+    int rc;
 
     assert(node);
     memset(&set, 0, sizeof set);
 
     if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
-        if (lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, 1, line)) {
-            return -1;
+        rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
+        if (rc) {
+            if (rc == 1) {
+                LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
+            }
+            return rc;
         }
 
-        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, 1);
-
+        /* set boolean result of the condition */
+        lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
         if (!set.value.bool) {
-            if (!first) {
-                LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
-            }
-            return 1;
+            ly_vlog_hide(1);
+            LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
+            ly_vlog_hide(0);
+            node->when_status |= LYD_WHEN_FALSE;
+            goto success;
         }
     }
 
@@ -4097,17 +4111,21 @@
                     return -1;
                 }
             }
-            if (lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, 1, line)) {
-                return -1;
+            rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
+            if (rc) {
+                if (rc == 1) {
+                    LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
+                }
+                return rc;
             }
 
-            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
-
+            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
             if (!set.value.bool) {
-                if (!first) {
-                    LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_uses *)parent)->when->cond);
-                }
-                return 1;
+                ly_vlog_hide(1);
+                LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_uses *)parent)->when->cond);
+                ly_vlog_hide(0);
+                node->when_status |= LYD_WHEN_FALSE;
+                goto success;
             }
         }
 
@@ -4120,23 +4138,31 @@
                     return -1;
                 }
             }
-            if (lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, 1, line)) {
-                return -1;
+            rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
+            if (rc) {
+                if (rc == 1) {
+                    LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
+                }
+                return rc;
             }
 
-            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, 1);
+            lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
 
             if (!set.value.bool) {
-                if (!first) {
-                    LOGVAL(LYE_NOCOND, line, LY_VLOG_LYS, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
-                }
-                return 1;
+                ly_vlog_hide(1);
+                LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
+                ly_vlog_hide(0);
+                node->when_status |= LYD_WHEN_FALSE;
+                goto success;
             }
         }
 
         parent = lys_parent(parent);
     }
 
+    node->when_status |= LYD_WHEN_TRUE;
+
+success:
     return 0;
 }
 
@@ -4148,14 +4174,12 @@
  * @param[in] type Type of the unresolved item.
  * @param[in] str_snode String, a schema node, or NULL.
  * @param[in] unres Unres schema structure to use.
- * @param[in] first Whether this is the first resolution try.
- * @param[in] line Line in the input file. 0 skips line print.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 static int
 resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
-                          struct unres_schema *unres, int first, uint32_t line)
+                          struct unres_schema *unres)
 {
     int rc = -1, has_str = 0, tpdf_flag = 0;
     struct lys_node *node;
@@ -4173,14 +4197,14 @@
         has_str = 1;
         ident = item;
 
-        rc = resolve_base_ident(mod, ident, base_name, "identity", first, line, NULL);
+        rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
         break;
     case UNRES_TYPE_IDENTREF:
         base_name = str_snode;
         has_str = 1;
         stype = item;
 
-        rc = resolve_base_ident(mod, NULL, base_name, "type", first, line, stype);
+        rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
         break;
     case UNRES_TYPE_LEAFREF:
         node = str_snode;
@@ -4194,7 +4218,7 @@
             node = (struct lys_node *)stype->parent;
         }
 
-        rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag, first, line,
+        rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
                                      (const struct lys_node **)&stype->info.lref.target);
         if (stype->info.lref.target) {
             /* store the backlink from leafref target */
@@ -4232,17 +4256,17 @@
         has_str = 1;
         feat_ptr = item;
 
-        rc = resolve_feature(base_name, mod, first, line, feat_ptr);
+        rc = resolve_feature(base_name, mod, feat_ptr);
         break;
     case UNRES_USES:
-        rc = resolve_unres_schema_uses(item, unres, first, line);
+        rc = resolve_unres_schema_uses(item, unres);
         break;
     case UNRES_TYPE_DFLT:
         base_name = str_snode;
         has_str = 1;
         stype = item;
 
-        rc = check_default(stype, base_name, mod, first, line);
+        rc = check_default(stype, base_name, mod);
         break;
     case UNRES_CHOICE_DFLT:
         base_name = str_snode;
@@ -4258,14 +4282,14 @@
         break;
     case UNRES_LIST_KEYS:
         has_str = 1;
-        rc = resolve_list_keys(item, str_snode, first, line);
+        rc = resolve_list_keys(item, str_snode);
         break;
     case UNRES_LIST_UNIQ:
         has_str = 1;
-        rc = resolve_unique(item, str_snode, first, line);
+        rc = resolve_unique(item, str_snode);
         break;
     case UNRES_AUGMENT:
-        rc = resolve_augment(item, NULL, first, line);
+        rc = resolve_augment(item, NULL);
         break;
     default:
         LOGINT;
@@ -4281,50 +4305,44 @@
 
 /* logs directly */
 static void
-print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node, uint32_t line)
+print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
 {
-    char line_str[18];
-
-    if (line) {
-        sprintf(line_str, " (line %u)", line);
-    } else {
-        line_str[0] = '\0';
-    }
-
     switch (type) {
     case UNRES_IDENT:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identity", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
         break;
     case UNRES_TYPE_IDENTREF:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "identityref", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
         break;
     case UNRES_TYPE_LEAFREF:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "leafref", ((struct lys_type *)item)->info.lref.path, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
+               ((struct lys_type *)item)->info.lref.path);
         break;
     case UNRES_TYPE_DER:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "derived type",
-               ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type",
+               ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value);
         break;
     case UNRES_IFFEAT:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "if-feature", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
         break;
     case UNRES_USES:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "uses", ((struct lys_node_uses *)item)->name, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
         break;
     case UNRES_TYPE_DFLT:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "type default", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
         break;
     case UNRES_CHOICE_DFLT:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "choice default", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
         break;
     case UNRES_LIST_KEYS:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list keys", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
         break;
     case UNRES_LIST_UNIQ:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "list unique", (char *)str_node, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
         break;
     case UNRES_AUGMENT:
-        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later%s.", "augment target", ((struct lys_node_augment *)item)->target_name, line_str);
+        LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
+               ((struct lys_node_augment *)item)->target_name);
         break;
     default:
         LOGINT;
@@ -4343,12 +4361,13 @@
 int
 resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
 {
-    uint32_t i, resolved, unres_count, res_count;
+    uint32_t i, resolved = 0, unres_count, res_count;
     int rc;
 
     assert(unres);
 
-    resolved = 0;
+    LOGVRB("Resolving unresolved schema nodes and their constraints.");
+    ly_vlog_hide(1);
 
     /* uses */
     do {
@@ -4363,13 +4382,13 @@
             }
 
             ++unres_count;
-            rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
-                                           LOGLINE_IDX(unres, i));
+            rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
             if (!rc) {
                 unres->type[i] = UNRES_RESOLVED;
                 ++resolved;
                 ++res_count;
             } else if (rc == -1) {
+                ly_vlog_hide(0);
                 return -1;
             }
         }
@@ -4385,20 +4404,33 @@
             continue;
         }
 
-        rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0,
-                                       LOGLINE_IDX(unres, i));
-        if (rc) {
+        rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+        if (rc == 0) {
+            unres->type[i] = UNRES_RESOLVED;
+            ++resolved;
+        } else if (rc == -1) {
+            ly_vlog_hide(0);
             return rc;
         }
-
-        unres->type[i] = UNRES_RESOLVED;
-        ++resolved;
     }
 
+    ly_vlog_hide(0);
+
     if (resolved < unres->count) {
+        /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
+         * all the validation errors
+         */
+        for (i = 0; i < unres->count; ++i) {
+            if (unres->type[i] == UNRES_RESOLVED) {
+                continue;
+            }
+            resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
+        }
         return -1;
     }
 
+    LOGVRB("Resolving unresolved schema nodes and their constraints.");
+
     unres->count = 0;
     return EXIT_SUCCESS;
 }
@@ -4411,15 +4443,14 @@
  * @param[in] item Item to resolve. Type determined by \p type.
  * @param[in] type Type of the unresolved item.
  * @param[in] str String argument.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
  */
 int
-unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, const char *str,
-                     uint32_t line)
+unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
+                     const char *str)
 {
-    return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)lydict_insert(mod->ctx, str, 0), line);
+    return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)lydict_insert(mod->ctx, str, 0));
 }
 
 /**
@@ -4430,26 +4461,35 @@
  * @param[in] item Item to resolve. Type determined by \p type.
  * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
  * @param[in] snode Schema node argument.
- * @param[in] line Line in the input file.
  *
  * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
  */
 int
 unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
-                      struct lys_node *snode, uint32_t line)
+                      struct lys_node *snode)
 {
     int rc;
     struct lyxml_elem *yin;
+    char *path, *msg;
 
     assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
            && (type != UNRES_MUST)));
 
-    rc = resolve_unres_schema_item(mod, item, type, snode, unres, 1, line);
+    ly_vlog_hide(1);
+    rc = resolve_unres_schema_item(mod, item, type, snode, unres);
+    ly_vlog_hide(0);
     if (rc != EXIT_FAILURE) {
+        if (rc == -1 && ly_errno == LY_EVALID) {
+            path = strdup(ly_errpath());
+            LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
+                   path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
+            free(path);
+            free(msg);
+        }
         return rc;
     }
 
-    print_unres_schema_item_fail(item, type, snode, line);
+    print_unres_schema_item_fail(item, type, snode);
 
     /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
     if (type == UNRES_TYPE_DER) {
@@ -4483,14 +4523,6 @@
         return -1;
     }
     unres->module[unres->count-1] = mod;
-#ifndef NDEBUG
-    unres->line = ly_realloc(unres->line, unres->count*sizeof *unres->line);
-    if (!unres->line) {
-        LOGMEM;
-        return -1;
-    }
-    unres->line[unres->count-1] = line;
-#endif
 
     return EXIT_SUCCESS;
 }
@@ -4520,12 +4552,12 @@
     }
 
     if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
-        if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
+        if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
             LOGINT;
             return -1;
         }
     } else {
-        if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i], 0) == -1) {
+        if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
             LOGINT;
             return -1;
         }
@@ -4580,62 +4612,21 @@
         free((*unres)->type);
         free((*unres)->str_snode);
         free((*unres)->module);
-#ifndef NDEBUG
-        free((*unres)->line);
-#endif
         free((*unres));
         (*unres) = NULL;
     }
 }
 
-/* logs directly */
-static void
-print_unres_data_item_fail(struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
-{
-    struct lys_node_leaf *sleaf;
-    char line_str[18];
-
-    if (line) {
-        sprintf(line_str, " (line %u)", line);
-    } else {
-        line_str[0] = '\0';
-    }
-
-    sleaf = (struct lys_node_leaf *)node->schema;
-
-    switch (type) {
-    case UNRES_LEAFREF:
-        LOGVRB("Leafref \"%s\" could not be resolved, it will be attempted later%s.",
-               sleaf->type.info.lref.path, line_str);
-        break;
-    case UNRES_INSTID:
-        LOGVRB("Instance-identifier \"%s\" could not be resolved, it will be attempted later%s.",
-               ((struct lyd_node_leaf_list *)node)->value_str, line_str);
-        break;
-    case UNRES_WHEN:
-        LOGVRB("There was an unsatisfied when condition, evaluation will be attempted later%s.", line_str);
-        break;
-    case UNRES_MUST:
-        LOGVRB("There was an unsatisfied must condition, evaluation will be attempted later%s.", line_str);
-        break;
-    default:
-        LOGINT;
-        break;
-    }
-}
-
 /**
  * @brief Resolve a single unres data item. Logs directly.
  *
  * @param[in] node Data node to resolve.
- * @param[in] first Whether this is the first resolution try.
  * @param[in] type Type of the unresolved item.
- * @param[in] line Line in the input file. 0 skips line print.
  *
  * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
  */
 int
-resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int first, uint32_t line)
+resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
 {
     uint32_t i;
     int rc;
@@ -4650,7 +4641,7 @@
     switch (type) {
     case UNRES_LEAFREF:
         assert(sleaf->type.base == LY_TYPE_LEAFREF);
-        if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, first, line, &matches))) {
+        if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches))) {
             return rc;
         }
 
@@ -4667,10 +4658,8 @@
 
         if (!leaf->value.leafref) {
             /* reference not found */
-            if (!first) {
-                LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
-                LOGVAL(LYE_SPEC, 0, 0, NULL, "Leafref value \"%s\" did not match any node value.", leaf->value_str);
-            }
+            LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
+            LOGVAL(LYE_SPEC, LY_VLOG_LYD, leaf, "Leafref value \"%s\" did not match any node value.", leaf->value_str);
             return EXIT_FAILURE;
         }
         break;
@@ -4678,14 +4667,12 @@
     case UNRES_INSTID:
         assert(sleaf->type.base == LY_TYPE_INST);
         ly_errno = 0;
-        leaf->value.instance = resolve_instid(node, leaf->value_str, line);
+        leaf->value.instance = resolve_instid(node, leaf->value_str);
         if (!leaf->value.instance) {
             if (ly_errno) {
                 return -1;
             } else if (sleaf->type.info.inst.req > -1) {
-                if (!first) {
-                    LOGVAL(LYE_NORESOLV, line, LY_VLOG_LYD, leaf, leaf->value_str);
-                }
+                LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, leaf->value_str);
                 return EXIT_FAILURE;
             } else {
                 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
@@ -4694,13 +4681,13 @@
         break;
 
     case UNRES_WHEN:
-        if ((rc = resolve_when(node, first, line))) {
+        if ((rc = resolve_when(node))) {
             return rc;
         }
         break;
 
     case UNRES_MUST:
-        if ((rc = resolve_must(node, first, line))) {
+        if ((rc = resolve_must(node))) {
             return rc;
         }
         break;
@@ -4714,29 +4701,20 @@
 }
 
 /**
- * @brief Try to resolve an unres data item. Logs indirectly.
+ * @brief add data unres item
  *
  * @param[in] unres Unres data structure to use.
  * @param[in] node Data node to use.
- * @param[in] line Line in the input file.
  *
- * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
+ * @return 0 on success, -1 on error.
  */
 int
-unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type, uint32_t line)
+unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
 {
-    int rc;
+    assert(unres && node);
+    assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
 
-    assert(unres && node && ((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)));
-
-    rc = resolve_unres_data_item(node, type, 1, line);
-    if (rc != EXIT_FAILURE) {
-        return rc;
-    }
-
-    print_unres_data_item_fail(node, type, line);
-
-    ++unres->count;
+    unres->count++;
     unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
     if (!unres->node) {
         LOGMEM;
@@ -4749,14 +4727,11 @@
         return -1;
     }
     unres->type[unres->count - 1] = type;
-#ifndef NDEBUG
-    unres->line = ly_realloc(unres->line, unres->count * sizeof *unres->line);
-    if (!unres->line) {
-        LOGMEM;
-        return -1;
+
+    if (type == UNRES_WHEN) {
+        /* remove previous result */
+        node->when_status = LYD_WHEN;
     }
-    unres->line[unres->count - 1] = line;
-#endif
 
     return EXIT_SUCCESS;
 }
@@ -4765,21 +4740,171 @@
  * @brief Resolve every unres data item in the structure. Logs directly.
  *
  * @param[in] unres Unres data structure to use.
+ * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
+ * NULL and when condition is false the error is raised.
  *
  * @return EXIT_SUCCESS on success, -1 on error.
  */
 int
-resolve_unres_data(struct unres_data *unres)
+resolve_unres_data(struct unres_data *unres, struct lyd_node **root)
 {
-    uint32_t i;
-    int rc;
+    uint32_t i, j = 0, resolved = 0, del_items = 0, when_stmt = 0;
+    int rc, progress;
+    char *msg, *path;
+    struct lyd_node *parent;
 
+    assert(unres);
+    assert(root && (*root));
+
+    if (!unres->count) {
+        return EXIT_SUCCESS;
+    }
+
+    LOGVRB("Resolving unresolved data nodes and their constraints.");
+    ly_vlog_hide(1);
+
+    /* when-stmt first */
+    ly_errno = LY_SUCCESS;
+    ly_vecode = LYVE_SUCCESS;
+    do {
+        progress = 0;
+        for(i = 0; i < unres->count; i++) {
+            if (unres->type[i] != UNRES_WHEN) {
+                continue;
+            }
+            if (!j) {
+                /* count when-stmt nodes in unres list */
+                when_stmt++;
+            }
+
+            /* resolve when condition only when all parent when conditions are already resolved */
+            for (parent = unres->node[i]->parent;
+                 parent && LYD_WHEN_DONE(parent->when_status);
+                 parent = parent->parent) {
+                if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
+                    /* the parent node was already unlinked, do not resolve this node,
+                     *  it will be removed anyway, so just mark it as resolved
+                     */
+                    unres->node[i]->when_status |= LYD_WHEN_FALSE;
+                    unres->type[i] = UNRES_RESOLVED;
+                    resolved++;
+                    break;
+                }
+            }
+            if (parent) {
+                continue;
+            }
+
+            rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
+            if (!rc) {
+                if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
+                    if (!root) {
+                        /* false when condition */
+                        ly_vlog_hide(0);
+                        path = strdup(ly_errpath());
+                        LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
+                               path[0] ? path : "", path[0] ? ")" : "");
+                        free(path);
+                        free(msg);
+                        return -1;
+                    } /* follows else */
+
+                    /* auto-delete */
+                    LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
+                                    ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
+                    if (*root == unres->node[i]) {
+                        *root = (*root)->next;
+                    }
+
+                    /* only unlink now, the subtree can contain another nodes stored in the unres list */
+                    lyd_unlink(unres->node[i]);
+                    unres->type[i] = UNRES_DELETE;
+                    del_items++;
+                } else {
+                    unres->type[i] = UNRES_RESOLVED;
+                }
+                ly_errno = LY_SUCCESS;
+                ly_vecode = LYVE_SUCCESS;
+                resolved++;
+                progress = 1;
+            } else if (rc == -1) {
+                ly_vlog_hide(0);
+                return -1;
+            }
+        }
+        j = 1;
+    } while (progress && resolved < when_stmt);
+
+    /* do we have some unresolved when-stmt? */
+    if (when_stmt != resolved) {
+        ly_vlog_hide(0);
+        path = strdup(ly_errpath());
+        LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
+               path[0] ? path : "", path[0] ? ")" : "");
+        free(path);
+        free(msg);
+        return -1;
+    }
+
+    for (i = 0; del_items && i < unres->count; i++) {
+        /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
+        if (unres->type[i] != UNRES_DELETE) {
+            continue;
+        }
+
+        for (j = 0; j < unres->count; j++) {
+            if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
+                continue;
+            }
+
+            /* test if the node is in subtree to be deleted */
+            for (parent = unres->node[j]; parent; parent = parent->parent) {
+                if (parent == unres->node[i]) {
+                    /* yes, it is */
+                    unres->type[j] = UNRES_RESOLVED;
+                    resolved++;
+                    break;
+                }
+            }
+        }
+
+        /* really remove the complete subtree */
+        lyd_free(unres->node[i]);
+        unres->type[i] = UNRES_RESOLVED;
+        del_items--;
+    }
+
+    /* rest */
     for (i = 0; i < unres->count; ++i) {
-        rc = resolve_unres_data_item(unres->node[i], unres->type[i], 0, LOGLINE_IDX(unres, i));
-        if (rc) {
+        if (unres->type[i] == UNRES_RESOLVED) {
+            continue;
+        }
+
+        rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
+        if (rc == 0) {
+            unres->type[i] = UNRES_RESOLVED;
+            resolved++;
+        } else if (rc == -1) {
+            ly_vlog_hide(0);
             return -1;
         }
     }
 
+    ly_vlog_hide(0);
+    if (resolved < unres->count) {
+        /* try to resolve the unresolved data again, it will not resolve anything, but it will print
+         * all the validation errors
+         */
+        for (i = 0; i < unres->count; ++i) {
+            if (unres->type[i] == UNRES_RESOLVED) {
+                continue;
+            }
+            resolve_unres_data_item(unres->node[i], unres->type[i]);
+        }
+        return -1;
+    }
+
+    LOGVRB("All data nodes and constraints resolved");
+    unres->count = 0;
     return EXIT_SUCCESS;
 }