path FEATURE new compiled path structure (#1108)

Refactoring includes using it for
instance-identifier and for checking leafref,
it is evaluated using stanrad XPath. Predicates
used for lyd_new_list2(), tests included.
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 4c7ca02..058b19a 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -26,6 +26,7 @@
 #include "context.h"
 #include "dict.h"
 #include "log.h"
+#include "path.h"
 #include "plugins_exts.h"
 #include "plugins_types.h"
 #include "plugins_exts_internal.h"
@@ -858,7 +859,7 @@
 
     *when = calloc(1, sizeof **when);
     (*when)->refcount = 1;
-    (*when)->cond = lyxp_expr_parse(ctx->ctx, when_p->cond);
+    (*when)->cond = lyxp_expr_parse(ctx->ctx, when_p->cond, 0, 1);
     (*when)->module = ctx->mod_def;
     (*when)->context = lysc_xpath_context(node);
     DUP_STRING(ctx->ctx, when_p->dsc, (*when)->dsc);
@@ -883,7 +884,7 @@
 {
     LY_ERR ret = LY_SUCCESS;
 
-    must->cond = lyxp_expr_parse(ctx->ctx, must_p->arg);
+    must->cond = lyxp_expr_parse(ctx->ctx, must_p->arg, 0, 1);
     LY_CHECK_ERR_GOTO(!must->cond, ret = ly_errcode(ctx->ctx), done);
     must->module = ctx->mod_def;
     DUP_STRING(ctx->ctx, must_p->eapptag, must->eapptag);
@@ -2300,239 +2301,6 @@
     return ret;
 }
 
-#define MOVE_PATH_PARENT(NODE, LIMIT_COND, TERM, ERR_MSG, ...) \
-    for ((NODE) = (NODE)->parent; \
-         (NODE) && !((NODE)->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_NOTIF | LYS_RPC | LYS_ACTION)); \
-         (NODE) = (NODE)->parent); \
-    if (!(NODE) && (LIMIT_COND)) { /* we are going higher than top-level */ \
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE, ERR_MSG, ##__VA_ARGS__); \
-        TERM; \
-    }
-
-/**
- * @brief Validate the predicate(s) from the leafref path.
- * @param[in] ctx Compile context
- * @param[in, out] predicate Pointer to the predicate in the leafref path. The pointer is moved after the validated predicate(s).
- * Since there can be multiple adjacent predicates for lists with multiple keys, all such predicates are validated.
- * @param[in] start_node Path context node (where the path is instantiated).
- * @param[in] context_node Predicate context node (where the predicate is placed).
- * @param[in] path_context Schema where the path was defined to correct resolve of the prefixes.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
-static LY_ERR
-lys_compile_leafref_predicate_validate(struct lysc_ctx *ctx, const char **predicate, const struct lysc_node *start_node,
-                                       const struct lysc_node_list *context_node, const struct lys_module *path_context)
-{
-    LY_ERR ret = LY_EVALID;
-    const struct lys_module *mod;
-    const struct lysc_node *src_node, *dst_node;
-    const char *path_key_expr, *pke_start, *src, *src_prefix, *dst, *dst_prefix;
-    size_t src_len, src_prefix_len, dst_len, dst_prefix_len;
-    unsigned int dest_parent_times, c;
-    const char *start, *end, *pke_end;
-    struct ly_set keys = {0};
-    int i;
-
-    assert(path_context);
-
-    while (**predicate == '[') {
-        start = (*predicate)++;
-
-        while (isspace(**predicate)) {
-            ++(*predicate);
-        }
-        LY_CHECK_GOTO(ly_parse_nodeid(predicate, &src_prefix, &src_prefix_len, &src, &src_len), cleanup);
-        while (isspace(**predicate)) {
-            ++(*predicate);
-        }
-        if (**predicate != '=') {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - missing \"=\" after node-identifier.",
-                   *predicate - start + 1, start);
-            goto cleanup;
-        }
-        ++(*predicate);
-        while (isspace(**predicate)) {
-            ++(*predicate);
-        }
-
-        if ((end = pke_end = strchr(*predicate, ']')) == NULL) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%s\" - missing predicate termination.", start);
-            goto cleanup;
-        }
-        --pke_end;
-        while (isspace(*pke_end)) {
-            --pke_end;
-        }
-        ++pke_end;
-        /* localize path-key-expr */
-        pke_start = path_key_expr = *predicate;
-        /* move after the current predicate */
-        *predicate = end + 1;
-
-        /* source (must be leaf or leaf-list) */
-        if (src_prefix) {
-            mod = lys_module_find_prefix(path_context, src_prefix, src_prefix_len);
-            if (!mod) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                       "Invalid leafref path predicate \"%.*s\" - prefix \"%.*s\" not defined in module \"%s\".",
-                       *predicate - start, start, src_prefix_len, src_prefix, path_context->name);
-                goto cleanup;
-            }
-            if (!mod->implemented) {
-                /* make the module implemented */
-                lys_set_implemented_internal((struct lys_module*)mod, 2);
-            }
-        } else {
-            mod = start_node->module;
-        }
-        src_node = NULL;
-        if (!(context_node->flags & LYS_KEYLESS)) {
-            struct lysc_node *key;
-            for (key = context_node->child; key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY); key = key->next) {
-                if (!ly_strncmp(key->name, src, src_len)) {
-                    src_node = key;
-                    break;
-                }
-            }
-        }
-        if (!src_node) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - predicate's key node \"%.*s\" not found.",
-                   *predicate - start, start, src_len, src, mod->name);
-            goto cleanup;
-        }
-
-        /* check that there is only one predicate for the */
-        c = keys.count;
-        i = ly_set_add(&keys, (void*)src_node, 0);
-        LY_CHECK_GOTO(i == -1, cleanup);
-        if (keys.count == c) { /* node was already present in the set */
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - multiple equality tests for the key \"%s\".",
-                   *predicate - start, start, src_node->name);
-            goto cleanup;
-        }
-
-        /* destination */
-        dest_parent_times = 0;
-        dst_node = start_node;
-
-        /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
-        if (strncmp(path_key_expr, "current", 7)) {
-error_current_function_invocation:
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - missing current-function-invocation.",
-                   *predicate - start, start);
-            goto cleanup;
-        }
-        for (path_key_expr += 7; isspace(*path_key_expr); ++path_key_expr);
-        if (*path_key_expr != '(') {
-            goto error_current_function_invocation;
-        }
-        for (path_key_expr++; isspace(*path_key_expr); ++path_key_expr);
-        if (*path_key_expr != ')') {
-            goto error_current_function_invocation;
-        }
-        for (path_key_expr++; isspace(*path_key_expr); ++path_key_expr);
-
-        if (*path_key_expr != '/') {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - missing \"/\" after current-function-invocation.",
-                   *predicate - start, start);
-            goto cleanup;
-        }
-        ++path_key_expr;
-        while (isspace(*path_key_expr)) {
-            ++path_key_expr;
-        }
-
-        /* rel-path-keyexpr:
-         * 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier */
-        while (!strncmp(path_key_expr, "..", 2)) {
-            ++dest_parent_times;
-            path_key_expr += 2;
-            while (isspace(*path_key_expr)) {
-                ++path_key_expr;
-            }
-            if (*path_key_expr != '/') {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                       "Invalid leafref path predicate \"%.*s\" - missing \"/\" in \"../\" rel-path-keyexpr pattern.",
-                       *predicate - start, start);
-                goto cleanup;
-            }
-            ++path_key_expr;
-            while (isspace(*path_key_expr)) {
-                ++path_key_expr;
-            }
-
-            /* path is supposed to be evaluated in data tree, so we have to skip
-             * all schema nodes that cannot be instantiated in data tree */
-            MOVE_PATH_PARENT(dst_node, !strncmp(path_key_expr, "..", 2), goto cleanup,
-                             "Invalid leafref path predicate \"%.*s\" - too many \"..\" in rel-path-keyexpr.",
-                             *predicate - start, start);
-        }
-        if (!dest_parent_times) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - at least one \"..\" is expected in rel-path-keyexpr.",
-                   *predicate - start, start);
-            goto cleanup;
-        }
-        if (path_key_expr == pke_end) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - at least one node-identifier is expected in rel-path-keyexpr.",
-                   *predicate - start, start);
-            goto cleanup;
-        }
-
-        while(path_key_expr != pke_end) {
-            for (;*path_key_expr == '/' || isspace(*path_key_expr); ++path_key_expr);
-            if (ly_parse_nodeid(&path_key_expr, &dst_prefix, &dst_prefix_len, &dst, &dst_len)) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
-                       "Invalid node identifier in leafref path predicate - character %d (of %.*s).",
-                       path_key_expr - start + 1, *predicate - start, start);
-                goto cleanup;
-            }
-
-            if (dst_prefix) {
-                mod = lys_module_find_prefix(path_context, dst_prefix, dst_prefix_len);
-            } else {
-                mod = start_node->module;
-            }
-            if (!mod) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                       "Invalid leafref path predicate \"%.*s\" - unable to find module of the node \"%.*s\" in rel-path-keyexpr.",
-                       *predicate - start, start, dst_len, dst);
-                goto cleanup;
-            }
-            if (!mod->implemented) {
-                /* make the module implemented */
-                lys_set_implemented_internal((struct lys_module*)mod, 2);
-            }
-
-            dst_node = lys_find_child(dst_node, mod, dst, dst_len, 0, LYS_GETNEXT_NOSTATECHECK);
-            if (!dst_node) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                       "Invalid leafref path predicate \"%.*s\" - unable to find node \"%.*s\" in the rel-path-keyexpr.",
-                       *predicate - start, start, path_key_expr - pke_start, pke_start);
-                goto cleanup;
-            }
-        }
-        if (!(dst_node->nodetype & (dst_node->module->version < LYS_VERSION_1_1 ? LYS_LEAF : LYS_LEAF | LYS_LEAFLIST))) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path predicate \"%.*s\" - rel-path-keyexpr \"%.*s\" refers %s instead of leaf.",
-                   *predicate - start, start, path_key_expr - pke_start, pke_start, lys_nodetype2str(dst_node->nodetype));
-            goto cleanup;
-        }
-    }
-
-    ret = LY_SUCCESS;
-cleanup:
-    ly_set_erase(&keys, NULL);
-    return ret;
-}
-
 /**
  * @brief Parse path-arg (leafref). Get tokens of the path by repetitive calls of the function.
  *
@@ -2662,153 +2430,10 @@
     return ret;
 }
 
-/**
- * @brief Validate the leafref path.
- * @param[in] ctx Compile context
- * @param[in] startnode Path context node (where the leafref path begins/is placed).
- * @param[in] leafref Leafref to validate.
- * @param[out] target Optional resolved leafref target.
- * @return LY_ERR value - LY_SUCCESS or LY_EVALID.
- */
-LY_ERR
-lys_compile_leafref_validate(struct lysc_ctx *ctx, struct lysc_node *startnode, struct lysc_type_leafref *leafref,
-                             const struct lysc_node **target)
-{
-    const struct lysc_node *node = NULL, *parent = NULL;
-    const struct lys_module *mod;
-    struct lysc_type *type;
-    const char *id, *prefix, *name;
-    size_t prefix_len, name_len;
-    int parent_times = 0, has_predicate;
-    unsigned int iter, u;
-    LY_ERR ret = LY_SUCCESS;
+static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+                               struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
+                               struct lysc_type **type, const char **units);
 
-    assert(ctx);
-    assert(startnode);
-    assert(leafref);
-
-    ctx->path[0] = '\0';
-    lysc_path(startnode, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
-    ctx->path_len = strlen(ctx->path);
-
-    iter = 0;
-    id = leafref->path;
-
-    if (!*id) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG, "Empty leafref path.");
-        return LY_EVALID;
-    }
-
-    while(*id && (ret = lys_path_token(&id, &prefix, &prefix_len, &name, &name_len, &parent_times, &has_predicate)) == LY_SUCCESS) {
-        if (!iter) { /* first iteration */
-            /* precess ".." in relative paths */
-            if (parent_times > 0) {
-                /* move from the context node */
-                for (u = 0, parent = startnode; u < (unsigned int)parent_times; u++) {
-                    /* path is supposed to be evaluated in data tree, so we have to skip
-                    * all schema nodes that cannot be instantiated in data tree */
-                    MOVE_PATH_PARENT(parent, u < (unsigned int)parent_times - 1, return LY_EVALID,
-                                     "Invalid leafref path \"%s\" - too many \"..\" in the path.", leafref->path);
-                }
-            }
-        }
-
-        if (prefix) {
-            mod = lys_module_find_prefix(leafref->path_context, prefix, prefix_len);
-        } else {
-            mod = startnode->module;
-        }
-        if (!mod) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path - unable to find module connected with the prefix of the node \"%.*s\".",
-                   id - leafref->path, leafref->path);
-            return LY_EVALID;
-        }
-        if (!mod->implemented) {
-            /* make the module implemented */
-            lys_set_implemented_internal((struct lys_module*)mod, 2);
-        }
-
-        node = lys_find_child(parent, mod, name, name_len, 0, LYS_GETNEXT_NOSTATECHECK);
-        if (!node) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path - unable to find \"%.*s\".", id - leafref->path, leafref->path);
-            return LY_EVALID;
-        }
-        parent = node;
-
-        if (has_predicate) {
-            /* we have predicate, so the current result must be list */
-            if (node->nodetype != LYS_LIST) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                       "Invalid leafref path - node \"%.*s\" is expected to be a list, but it is %s.",
-                       id - leafref->path, leafref->path, lys_nodetype2str(node->nodetype));
-                return LY_EVALID;
-            }
-
-            LY_CHECK_RET(lys_compile_leafref_predicate_validate(ctx, &id, startnode, (struct lysc_node_list*)node, leafref->path_context),
-                         LY_EVALID);
-        }
-
-        ++iter;
-    }
-    if (ret) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SYNTAX_YANG,
-               "Invalid leafref path at character %d (%s).", id - leafref->path + 1, leafref->path);
-        return LY_EVALID;
-    }
-
-    if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-               "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
-               leafref->path, lys_nodetype2str(node->nodetype));
-        return LY_EVALID;
-    }
-
-    /* check status */
-    if (lysc_check_status(ctx, startnode->flags, startnode->module, startnode->name, node->flags, node->module, node->name)) {
-        return LY_EVALID;
-    }
-
-    /* check config */
-    if (leafref->require_instance && (startnode->flags & LYS_CONFIG_W)) {
-        if (node->flags & LYS_CONFIG_R) {
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path \"%s\" - target is supposed to represent configuration data (as the leafref does), but it does not.",
-                   leafref->path);
-            return LY_EVALID;
-        }
-    }
-
-    /* store the target's type and check for circular chain of leafrefs */
-    leafref->realtype = ((struct lysc_node_leaf*)node)->type;
-    for (type = leafref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref*)type)->realtype) {
-        if (type == (struct lysc_type*)leafref) {
-            /* circular chain detected */
-            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-                   "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", leafref->path);
-            return LY_EVALID;
-        }
-    }
-
-    /* check if leafref and its target are under common if-features */
-    if (lys_compile_leafref_features_validate(startnode, node)) {
-        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
-               "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of features applicable to the leafref itself.",
-               leafref->path);
-        return LY_EVALID;
-    }
-
-    ctx->path_len = 1;
-    ctx->path[1] = '\0';
-    if (target) {
-        *target = node;
-    }
-    return LY_SUCCESS;
-}
-
-static LY_ERR lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags, struct lysp_module *context_mod, const char *context_name,
-                               struct lysp_type *type_p, struct lysc_type **type, const char **units);
 /**
  * @brief The core of the lys_compile_type() - compile information about the given type (from typedef or leaf/leaf-list).
  * @param[in] ctx Compile context.
@@ -2825,9 +2450,10 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags, struct lysp_module *context_mod, const char *context_name,
-                  struct lysp_type *type_p, struct lys_module *module, LY_DATA_TYPE basetype, const char *tpdfname,
-                  struct lysc_type *base,  struct lysc_type **type)
+lys_compile_type_(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+                  struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
+                  struct lys_module *module, LY_DATA_TYPE basetype, const char *tpdfname, struct lysc_type *base,
+                  struct lysc_type **type)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type_bin *bin;
@@ -2837,6 +2463,7 @@
     struct lysc_type_enum *enumeration;
     struct lysc_type_dec *dec;
     struct lysc_type_identityref *idref;
+    struct lysc_type_leafref *lref;
     struct lysc_type_union *un, *un_aux;
 
     switch (basetype) {
@@ -3045,6 +2672,8 @@
         }
         break;
     case LY_TYPE_LEAFREF:
+        lref = (struct lysc_type_leafref*)*type;
+
         /* RFC 7950 9.9.3 - require-instance */
         if (type_p->flags & LYS_SET_REQINST) {
             if (context_mod->mod->version < LYS_VERSION_1_1) {
@@ -3059,20 +2688,20 @@
                 }
                 return LY_EVALID;
             }
-            ((struct lysc_type_leafref*)(*type))->require_instance = type_p->require_instance;
+            lref->require_instance = type_p->require_instance;
         } else if (base) {
             /* inherit */
-            ((struct lysc_type_leafref*)(*type))->require_instance = ((struct lysc_type_leafref*)base)->require_instance;
+            lref->require_instance = ((struct lysc_type_leafref *)base)->require_instance;
         } else {
             /* default is true */
-            ((struct lysc_type_leafref*)(*type))->require_instance = 1;
+            lref->require_instance = 1;
         }
         if (type_p->path) {
-            DUP_STRING(ctx->ctx, (void*)type_p->path, ((struct lysc_type_leafref*)(*type))->path);
-            ((struct lysc_type_leafref*)(*type))->path_context = module;
+            lref->path = lyxp_expr_dup(ctx->ctx, type_p->path);
+            lref->path_context = module;
         } else if (base) {
-            DUP_STRING(ctx->ctx, ((struct lysc_type_leafref*)base)->path, ((struct lysc_type_leafref*)(*type))->path);
-            ((struct lysc_type_leafref*)(*type))->path_context = ((struct lysc_type_leafref*)base)->path_context;
+            lref->path = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref*)base)->path);
+            lref->path_context = ((struct lysc_type_leafref*)base)->path_context;
         } else if (tpdfname) {
             LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_MISSCHILDSTMT, "path", "leafref type ", tpdfname);
             return LY_EVALID;
@@ -3123,7 +2752,8 @@
             /* compile the type */
             LY_ARRAY_CREATE_RET(ctx->ctx, un->types, LY_ARRAY_SIZE(type_p->types), LY_EVALID);
             for (LY_ARRAY_SIZE_TYPE u = 0, additional = 0; u < LY_ARRAY_SIZE(type_p->types); ++u) {
-                LY_CHECK_RET(lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name, &type_p->types[u], &un->types[u + additional], NULL));
+                LY_CHECK_RET(lys_compile_type(ctx, context_node_p, context_flags, context_mod, context_name,
+                                              &type_p->types[u], &un->types[u + additional], NULL));
                 if (un->types[u + additional]->basetype == LY_TYPE_UNION) {
                     /* add space for additional types from the union subtype */
                     un_aux = (struct lysc_type_union *)un->types[u + additional];
@@ -3136,11 +2766,13 @@
                             /* duplicate the whole structure because of the instance-specific path resolving for realtype */
                             un->types[u + additional] = calloc(1, sizeof(struct lysc_type_leafref));
                             LY_CHECK_ERR_RET(!un->types[u + additional], LOGMEM(ctx->ctx);lysc_type_free(ctx->ctx, (struct lysc_type*)un_aux), LY_EMEM);
-                            ((struct lysc_type_leafref*)un->types[u + additional])->basetype = LY_TYPE_LEAFREF;
-                            DUP_STRING(ctx->ctx, ((struct lysc_type_leafref*)un_aux->types[v])->path, ((struct lysc_type_leafref*)un->types[u + additional])->path);
-                            ((struct lysc_type_leafref*)un->types[u + additional])->refcount = 1;
-                            ((struct lysc_type_leafref*)un->types[u + additional])->require_instance = ((struct lysc_type_leafref*)un_aux->types[v])->require_instance;
-                            ((struct lysc_type_leafref*)un->types[u + additional])->path_context = ((struct lysc_type_leafref*)un_aux->types[v])->path_context;
+                            lref = (struct lysc_type_leafref *)un->types[u + additional];
+
+                            lref->basetype = LY_TYPE_LEAFREF;
+                            lref->path = lyxp_expr_dup(ctx->ctx, ((struct lysc_type_leafref*)un_aux->types[v])->path);
+                            lref->refcount = 1;
+                            lref->require_instance = ((struct lysc_type_leafref*)un_aux->types[v])->require_instance;
+                            lref->path_context = ((struct lysc_type_leafref*)un_aux->types[v])->path_context;
                             /* TODO extensions */
 
                         } else {
@@ -3201,8 +2833,9 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags, struct lysp_module *context_mod, const char *context_name,
-                 struct lysp_type *type_p, struct lysc_type **type, const char **units)
+lys_compile_type(struct lysc_ctx *ctx, struct lysp_node *context_node_p, uint16_t context_flags,
+                 struct lysp_module *context_mod, const char *context_name, struct lysp_type *type_p,
+                 struct lysc_type **type, const char **units)
 {
     LY_ERR ret = LY_SUCCESS;
     unsigned int u;
@@ -3511,9 +3144,8 @@
  * @return LY_SUCCESS in case of unique name, LY_EEXIST otherwise.
  */
 static LY_ERR
-lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *children,
-                          const struct lysc_action *actions, const struct lysc_notif *notifs,
-                          const char *name, void *exclude)
+lys_compile_node_uniqness(struct lysc_ctx *ctx, const struct lysc_node *children, const struct lysc_action *actions,
+                          const struct lysc_notif *notifs, const char *name, void *exclude)
 {
     const struct lysc_node *iter;
     LY_ARRAY_SIZE_TYPE u;
@@ -3618,7 +3250,7 @@
 
     if ((action_p->input.musts || action_p->output.musts) && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, action, 0);
+        ly_set_add(&ctx->xpath, action, 0);
     }
 
 cleanup:
@@ -3680,7 +3312,7 @@
     COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, u, lys_compile_must, ret, cleanup);
     if (notif_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, notif, 0);
+        ly_set_add(&ctx->xpath, notif, 0);
     }
     COMPILE_EXTS_GOTO(ctx, notif_p->exts, notif->exts, notif, LYEXT_PAR_NODE, ret, cleanup);
 
@@ -3723,7 +3355,7 @@
     COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, u, lys_compile_must, ret, done);
     if (cont_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, cont, 0);
+        ly_set_add(&ctx->xpath, cont, 0);
     }
     COMPILE_ARRAY1_GOTO(ctx, cont_p->actions, cont->actions, node, u, lys_compile_action, 0, ret, done);
     COMPILE_ARRAY1_GOTO(ctx, cont_p->notifs, cont->notifs, node, u, lys_compile_notif, 0, ret, done);
@@ -3769,13 +3401,13 @@
     }
     if (leaf->type->basetype == LY_TYPE_LEAFREF) {
         /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
-        ly_set_add(&ctx->unres, leaf, 0);
+        ly_set_add(&ctx->leafrefs, leaf, 0);
     } else if (leaf->type->basetype == LY_TYPE_UNION) {
         LY_ARRAY_SIZE_TYPE u;
         LY_ARRAY_FOR(((struct lysc_type_union*)leaf->type)->types, u) {
             if (((struct lysc_type_union*)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
                 /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
-                ly_set_add(&ctx->unres, leaf, 0);
+                ly_set_add(&ctx->leafrefs, leaf, 0);
             }
         }
     } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
@@ -3808,7 +3440,7 @@
     COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, u, lys_compile_must, ret, done);
     if (leaf_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, leaf, 0);
+        ly_set_add(&ctx->xpath, leaf, 0);
     }
     if (leaf_p->units) {
         leaf->units = lydict_insert(ctx->ctx, leaf_p->units, 0);
@@ -3873,7 +3505,7 @@
     COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, u, lys_compile_must, ret, done);
     if (llist_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, llist, 0);
+        ly_set_add(&ctx->xpath, llist, 0);
     }
     if (llist_p->units) {
         llist->units = lydict_insert(ctx->ctx, llist_p->units, 0);
@@ -4076,7 +3708,7 @@
     COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, u, lys_compile_must, ret, done);
     if (list_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, list, 0);
+        ly_set_add(&ctx->xpath, list, 0);
     }
 
     /* keys */
@@ -4379,7 +4011,7 @@
     COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, u, lys_compile_must, ret, done);
     if (any_p->musts && !(ctx->options & LYSC_OPT_GROUPING)) {
         /* do not check "must" semantics in a grouping */
-        ly_set_add(&ctx->unres, any, 0);
+        ly_set_add(&ctx->xpath, any, 0);
     }
 
     if (any->flags & LYS_CONFIG_W) {
@@ -4498,7 +4130,7 @@
 
             if (!(ctx->options & LYSC_OPT_GROUPING)) {
                 /* do not check "when" semantics in a grouping */
-                ly_set_add(&ctx->unres, cs, 0);
+                ly_set_add(&ctx->xpath, cs, 0);
             }
         }
         COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, cs->iffeatures, u, lys_compile_iffeature, ret, error);
@@ -4802,7 +4434,7 @@
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* do not check "when" semantics in a grouping */
-                    ly_set_add(&ctx->unres, node, 0);
+                    ly_set_add(&ctx->xpath, node, 0);
                 }
 
                 when_shared = *when;
@@ -4812,7 +4444,7 @@
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* in this case check "when" again for all children because of dummy node check */
-                    ly_set_add(&ctx->unres, node, 0);
+                    ly_set_add(&ctx->xpath, node, 0);
                 }
             }
         }
@@ -5083,7 +4715,7 @@
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* do not check "when" semantics in a grouping */
-                    ly_set_add(&ctx->unres, child, 0);
+                    ly_set_add(&ctx->xpath, child, 0);
                 }
 
                 when_shared = *when;
@@ -5093,7 +4725,7 @@
 
                 if (!(ctx->options & LYSC_OPT_GROUPING)) {
                     /* in this case check "when" again for all children because of dummy node check */
-                    ly_set_add(&ctx->unres, child, 0);
+                    ly_set_add(&ctx->xpath, child, 0);
                 }
             }
         }
@@ -5322,7 +4954,7 @@
                        lys_nodetype2str(node->nodetype));
                 goto cleanup;
             }
-            ly_set_add(&ctx->unres, node, 0);
+            ly_set_add(&ctx->xpath, node, 0);
         }
 
         /* min/max-elements */
@@ -5680,7 +5312,7 @@
 
         if (!(ctx->options & LYSC_OPT_GROUPING)) {
             /* do not check "when" semantics in a grouping */
-            ly_set_add(&ctx->unres, node, 0);
+            ly_set_add(&ctx->xpath, node, 0);
         }
     }
     COMPILE_ARRAY_GOTO(ctx, node_p->iffeatures, node->iffeatures, u, lys_compile_iffeature, ret, error);
@@ -6137,7 +5769,7 @@
                                lys_nodetype2str(devs[u]->target->nodetype), "add", "must");
                         goto cleanup;
                     }
-                    ly_set_add(&ctx->unres, devs[u]->target, 0);
+                    ly_set_add(&ctx->xpath, devs[u]->target, 0);
                 }
 
                 /* *unique-stmt */
@@ -6996,7 +6628,7 @@
  * @return LY_ERR value
  */
 static LY_ERR
-lys_compile_check_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
+lys_compile_unres_when_cyclic(struct lyxp_set *set, const struct lysc_node *node)
 {
     struct lyxp_set tmp_set;
     struct lyxp_set_scnode *xp_scnode;
@@ -7086,7 +6718,7 @@
  * @return LY_ERR value
  */
 static LY_ERR
-lys_compile_check_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
+lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node)
 {
     struct lyxp_set tmp_set;
     uint32_t i;
@@ -7142,7 +6774,7 @@
 
     /* check "when" */
     LY_ARRAY_FOR(when, u) {
-        ret = lyxp_atomize(when[u]->cond, LYD_SCHEMA, when[u]->module, when[u]->context,
+        ret = lyxp_atomize(when[u]->cond, LYD_SCHEMA, when[u]->module, when[u]->context ? when[u]->context : node,
                            when[u]->context ? LYXP_NODE_ELEM : LYXP_NODE_ROOT_CONFIG, &tmp_set, opts);
         if (ret != LY_SUCCESS) {
             LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_SEMANTICS, "Invalid when condition \"%s\".", when[u]->cond->expr);
@@ -7171,7 +6803,7 @@
         }
 
         /* check cyclic dependencies */
-        ret = lys_compile_check_when_cyclic(&tmp_set, node);
+        ret = lys_compile_unres_when_cyclic(&tmp_set, node);
         LY_CHECK_GOTO(ret, cleanup);
 
         lyxp_set_free_content(&tmp_set);
@@ -7215,6 +6847,71 @@
 }
 
 static LY_ERR
+lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref)
+{
+    const struct lysc_node *target = NULL;
+    struct ly_path *p;
+    struct lysc_type *type;
+
+    assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
+
+    /* try to find the target */
+    LY_CHECK_RET(ly_path_compile(node->module, node, lref->path, LY_PATH_LREF_TRUE, lys_resolve_prefix, lref->path_context,
+                                 LYD_SCHEMA, &p));
+
+    /* get the target node */
+    target = p[LY_ARRAY_SIZE(p) - 1].node;
+    ly_path_free(node->module->ctx, p);
+
+    if (!(target->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
+        LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
+               "Invalid leafref path \"%s\" - target node is %s instead of leaf or leaf-list.",
+               lref->path->expr, lys_nodetype2str(target->nodetype));
+        return LY_EVALID;
+    }
+
+    /* check status */
+    ctx->path[0] = '\0';
+    lysc_path(node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+    ctx->path_len = strlen(ctx->path);
+    if (lysc_check_status(ctx, node->flags, node->module, node->name, target->flags, target->module, target->name)) {
+        return LY_EVALID;
+    }
+    ctx->path_len = 1;
+    ctx->path[1] = '\0';
+
+    /* check config */
+    if (lref->require_instance && (node->flags & LYS_CONFIG_W)) {
+        if (target->flags & LYS_CONFIG_R) {
+            LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE, "Invalid leafref path \"%s\" - target is supposed"
+                   " to represent configuration data (as the leafref does), but it does not.", lref->path->expr);
+            return LY_EVALID;
+        }
+    }
+
+    /* store the target's type and check for circular chain of leafrefs */
+    lref->realtype = ((struct lysc_node_leaf *)target)->type;
+    for (type = lref->realtype; type && type->basetype == LY_TYPE_LEAFREF; type = ((struct lysc_type_leafref *)type)->realtype) {
+        if (type == (struct lysc_type *)lref) {
+            /* circular chain detected */
+            LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
+                   "Invalid leafref path \"%s\" - circular chain of leafrefs detected.", lref->path->expr);
+            return LY_EVALID;
+        }
+    }
+
+    /* check if leafref and its target are under common if-features */
+    if (lys_compile_leafref_features_validate(node, target)) {
+        LOGVAL(ctx->ctx, LY_VLOG_LYSC, node, LYVE_REFERENCE,
+               "Invalid leafref path \"%s\" - set of features applicable to the leafref target is not a subset of"
+               " features applicable to the leafref itself.", lref->path->expr);
+        return LY_EVALID;
+    }
+
+    return LY_SUCCESS;
+}
+
+static LY_ERR
 lys_compile_ietf_netconf_wd_annotation(struct lysc_ctx *ctx, struct lys_module *mod)
 {
     struct lysc_ext_instance *ext;
@@ -7252,12 +6949,85 @@
     return ret;
 }
 
+static LY_ERR
+lys_compile_unres(struct lysc_ctx *ctx)
+{
+    struct lysc_node *node;
+    struct lysc_type *type, *typeiter;
+    struct lysc_type_leafref *lref;
+    LY_ARRAY_SIZE_TYPE v;
+    uint32_t i;
+
+    /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
+     * can be also leafref, in case it is already resolved, go through the chain and check that it does not
+     * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
+    for (i = 0; i < ctx->leafrefs.count; ++i) {
+        node = ctx->leafrefs.objs[i];
+        assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
+        type = ((struct lysc_node_leaf *)node)->type;
+        if (type->basetype == LY_TYPE_LEAFREF) {
+            LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, (struct lysc_type_leafref *)type));
+        } else if (type->basetype == LY_TYPE_UNION) {
+            LY_ARRAY_FOR(((struct lysc_type_union *)type)->types, v) {
+                if (((struct lysc_type_union *)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
+                    lref = (struct lysc_type_leafref *)((struct lysc_type_union *)type)->types[v];
+                    LY_CHECK_RET(lys_compile_unres_leafref(ctx, node, lref));
+                }
+            }
+        }
+    }
+    for (i = 0; i < ctx->leafrefs.count; ++i) {
+        /* store pointer to the real type */
+        type = ((struct lysc_node_leaf *)ctx->leafrefs.objs[i])->type;
+        if (type->basetype == LY_TYPE_LEAFREF) {
+            for (typeiter = ((struct lysc_type_leafref*)type)->realtype;
+                    typeiter->basetype == LY_TYPE_LEAFREF;
+                    typeiter = ((struct lysc_type_leafref*)typeiter)->realtype);
+            ((struct lysc_type_leafref*)type)->realtype = typeiter;
+        } else if (type->basetype == LY_TYPE_UNION) {
+            LY_ARRAY_FOR(((struct lysc_type_union*)type)->types, v) {
+                if (((struct lysc_type_union*)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
+                    for (typeiter = ((struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[v])->realtype;
+                            typeiter->basetype == LY_TYPE_LEAFREF;
+                            typeiter = ((struct lysc_type_leafref*)typeiter)->realtype);
+                    ((struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[v])->realtype = typeiter;
+                }
+            }
+        }
+    }
+
+    /* check xpath */
+    for (i = 0; i < ctx->xpath.count; ++i) {
+        LY_CHECK_RET(lys_compile_unres_xpath(ctx, ctx->xpath.objs[i]));
+    }
+
+    /* finish incomplete default values compilation */
+    for (i = 0; i < ctx->dflts.count; ++i) {
+        struct ly_err_item *err = NULL;
+        struct lysc_incomplete_dflt *r = ctx->dflts.objs[i];
+        LY_ERR ret;
+        ret = r->dflt->realtype->plugin->store(ctx->ctx, r->dflt->realtype, r->dflt->original, strlen(r->dflt->original),
+                                               LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_SECOND_CALL, lys_resolve_prefix,
+                                               (void*)r->dflt_mod, LYD_XML, r->context_node, NULL, r->dflt, NULL, &err);
+        if (err) {
+            ly_err_print(err);
+            ctx->path[0] = '\0';
+            lysc_path(r->context_node, LYSC_PATH_LOG, ctx->path, LYSC_CTX_BUFSIZE);
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                   "Invalid default - value does not fit the type (%s).", err->msg);
+            ly_err_free(err);
+        }
+        LY_CHECK_RET(ret);
+    }
+
+    return LY_SUCCESS;
+}
+
 LY_ERR
 lys_compile(struct lys_module *mod, int options)
 {
     struct lysc_ctx ctx = {0};
     struct lysc_module *mod_c;
-    struct lysc_type *type, *typeiter;
     struct lysp_module *sp;
     struct lysp_node *node_p;
     struct lysp_augment **augments = NULL;
@@ -7350,71 +7120,8 @@
     /* extension instances TODO cover extension instances from submodules */
     COMPILE_EXTS_GOTO(&ctx, sp->exts, mod_c->exts, mod_c, LYEXT_PAR_MODULE, ret, error);
 
-    /* validate leafref's paths and when/must xpaths */
-    /* for leafref, we need 2 rounds - first detects circular chain by storing the first referred type (which
-     * can be also leafref, in case it is already resolved, go through the chain and check that it does not
-     * point to the starting leafref type). The second round stores the first non-leafref type for later data validation. */
-    for (i = 0; i < ctx.unres.count; ++i) {
-        if (((struct lysc_node*)ctx.unres.objs[i])->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-            type = ((struct lysc_node_leaf*)ctx.unres.objs[i])->type;
-            if (type->basetype == LY_TYPE_LEAFREF) {
-                /* validate the path */
-                LY_CHECK_GOTO(ret = lys_compile_leafref_validate(&ctx, ((struct lysc_node*)ctx.unres.objs[i]), (struct lysc_type_leafref*)type, NULL), error);
-            } else if (type->basetype == LY_TYPE_UNION) {
-                LY_ARRAY_FOR(((struct lysc_type_union*)type)->types, v) {
-                    if (((struct lysc_type_union*)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
-                        /* validate the path */
-                        ret = lys_compile_leafref_validate(&ctx, ((struct lysc_node*)ctx.unres.objs[i]),
-                                                           (struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[v], NULL);
-                        LY_CHECK_GOTO(ret, error);
-                    }
-                }
-            }
-        }
-
-        /* check xpath */
-        LY_CHECK_GOTO(ret = lys_compile_check_xpath(&ctx, ctx.unres.objs[i]), error);
-    }
-    for (i = 0; i < ctx.unres.count; ++i) {
-        if (((struct lysc_node*)ctx.unres.objs[i])->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
-            type = ((struct lysc_node_leaf*)ctx.unres.objs[i])->type;
-            if (type->basetype == LY_TYPE_LEAFREF) {
-                /* store pointer to the real type */
-                for (typeiter = ((struct lysc_type_leafref*)type)->realtype;
-                        typeiter->basetype == LY_TYPE_LEAFREF;
-                        typeiter = ((struct lysc_type_leafref*)typeiter)->realtype);
-                ((struct lysc_type_leafref*)type)->realtype = typeiter;
-            } else if (type->basetype == LY_TYPE_UNION) {
-                LY_ARRAY_FOR(((struct lysc_type_union*)type)->types, v) {
-                    if (((struct lysc_type_union*)type)->types[v]->basetype == LY_TYPE_LEAFREF) {
-                        /* store pointer to the real type */
-                        for (typeiter = ((struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[v])->realtype;
-                                typeiter->basetype == LY_TYPE_LEAFREF;
-                                typeiter = ((struct lysc_type_leafref*)typeiter)->realtype);
-                        ((struct lysc_type_leafref*)((struct lysc_type_union*)type)->types[v])->realtype = typeiter;
-                    }
-                }
-            }
-        }
-    }
-
-    /* finish incomplete default values compilation */
-    for (i = 0; i < ctx.dflts.count; ++i) {
-        struct ly_err_item *err = NULL;
-        struct lysc_incomplete_dflt *r = ctx.dflts.objs[i];
-        ret = r->dflt->realtype->plugin->store(ctx.ctx, r->dflt->realtype, r->dflt->original, strlen(r->dflt->original),
-                                               LY_TYPE_OPTS_SCHEMA | LY_TYPE_OPTS_STORE | LY_TYPE_OPTS_SECOND_CALL, lys_resolve_prefix,
-                                               (void*)r->dflt_mod, LYD_XML, r->context_node, NULL, r->dflt, NULL, &err);
-        if (err) {
-            ly_err_print(err);
-            ctx.path[0] = '\0';
-            lysc_path(r->context_node, LYSC_PATH_LOG, ctx.path, LYSC_CTX_BUFSIZE);
-            LOGVAL(ctx.ctx, LY_VLOG_STR, ctx.path, LYVE_SEMANTICS,
-                   "Invalid default - value does not fit the type (%s).", err->msg);
-            ly_err_free(err);
-        }
-        LY_CHECK_GOTO(ret, error);
-    }
+    /* finish compilation for all unresolved items in the context */
+    LY_CHECK_GOTO(ret = lys_compile_unres(&ctx), error);
 
     /* validate non-instantiated groupings from the parsed schema,
      * without it we would accept even the schemas with invalid grouping specification */
@@ -7457,7 +7164,8 @@
     }
 
     ly_set_erase(&ctx.dflts, free);
-    ly_set_erase(&ctx.unres, NULL);
+    ly_set_erase(&ctx.xpath, NULL);
+    ly_set_erase(&ctx.leafrefs, NULL);
     ly_set_erase(&ctx.groupings, NULL);
     ly_set_erase(&ctx.tpdf_chain, NULL);
     LY_ARRAY_FREE(augments);
@@ -7483,7 +7191,8 @@
 error:
     lys_feature_precompile_revert(&ctx, mod);
     ly_set_erase(&ctx.dflts, free);
-    ly_set_erase(&ctx.unres, NULL);
+    ly_set_erase(&ctx.xpath, NULL);
+    ly_set_erase(&ctx.leafrefs, NULL);
     ly_set_erase(&ctx.groupings, NULL);
     ly_set_erase(&ctx.tpdf_chain, NULL);
     LY_ARRAY_FREE(augments);