schema compile FEATURE status checks for deviated definitions

Fixes #1718
diff --git a/src/plugins_types.c b/src/plugins_types.c
index d9d74bf..e8203d6 100644
--- a/src/plugins_types.c
+++ b/src/plugins_types.c
@@ -685,6 +685,81 @@
 }
 
 API LY_ERR
+lyplg_type_check_status(const struct lysc_node *ctx_node, uint16_t val_flags, LY_VALUE_FORMAT format, void *prefix_data,
+        const char *val_name, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    const struct lys_module *mod2;
+    uint16_t flg1, flg2;
+
+    if (format != LY_VALUE_SCHEMA) {
+        /* nothing/unable to check */
+        return LY_SUCCESS;
+    }
+
+    mod2 = ((struct lysp_module *)prefix_data)->mod;
+
+    if (mod2 == ctx_node->module) {
+        /* use flags of the context node since the definition is local */
+        flg1 = (ctx_node->flags & LYS_STATUS_MASK) ? (ctx_node->flags & LYS_STATUS_MASK) : LYS_STATUS_CURR;
+    } else {
+        /* definition is foreign (deviation, refine), always current */
+        flg1 = LYS_STATUS_CURR;
+    }
+    flg2 = (val_flags & LYS_STATUS_MASK) ? (val_flags & LYS_STATUS_MASK) : LYS_STATUS_CURR;
+
+    if ((flg1 < flg2) && (ctx_node->module == mod2)) {
+        ret = ly_err_new(err, LY_EVALID, LYVE_REFERENCE, NULL, NULL,
+                "A %s definition \"%s\" is not allowed to reference %s value \"%s\".",
+                flg1 == LYS_STATUS_CURR ? "current" : "deprecated", ctx_node->name,
+                flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", val_name);
+        return ret;
+    }
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
+lyplg_type_lypath_check_status(const struct lysc_node *ctx_node, const struct ly_path *path, LY_VALUE_FORMAT format,
+        void *prefix_data, struct ly_err_item **err)
+{
+    LY_ERR ret;
+    LY_ARRAY_COUNT_TYPE u;
+    const struct lys_module *val_mod;
+    const struct lysc_node *node;
+    uint16_t flg1, flg2;
+
+    if (format != LY_VALUE_SCHEMA) {
+        /* nothing to check */
+        return LY_SUCCESS;
+    }
+
+    val_mod = ((struct lysp_module *)prefix_data)->mod;
+    if (val_mod == ctx_node->module) {
+        /* use flags of the context node since the definition is local */
+        flg1 = (ctx_node->flags & LYS_STATUS_MASK) ? (ctx_node->flags & LYS_STATUS_MASK) : LYS_STATUS_CURR;
+    } else {
+        /* definition is foreign (deviation, refine), always current */
+        flg1 = LYS_STATUS_CURR;
+    }
+
+    LY_ARRAY_FOR(path, u) {
+        node = path[u].node;
+
+        flg2 = (node->flags & LYS_STATUS_MASK) ? (node->flags & LYS_STATUS_MASK) : LYS_STATUS_CURR;
+        if ((flg1 < flg2) && (val_mod == node->module)) {
+            ret = ly_err_new(err, LY_EVALID, LYVE_REFERENCE, NULL, NULL,
+                    "A %s definition \"%s\" is not allowed to reference %s value \"%s\".",
+                    flg1 == LYS_STATUS_CURR ? "current" : "deprecated", ctx_node->name,
+                    flg2 == LYS_STATUS_OBSLT ? "obsolete" : "deprecated", node->name);
+            return ret;
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+API LY_ERR
 lyplg_type_lypath_new(const struct ly_ctx *ctx, const char *value, size_t value_len, uint32_t options,
         LY_VALUE_FORMAT format, void *prefix_data, const struct lysc_node *ctx_node, struct lys_glob_unres *unres,
         struct ly_path **path, struct ly_err_item **err)
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 3330ad3..4e13ce1 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -136,6 +136,8 @@
  * - ::lyplg_type_get_prefix()
  *
  * - ::lyplg_type_check_hints()
+ * - ::lyplg_type_check_status()
+ * - ::lyplg_type_lypath_check_status()
  * - ::lyplg_type_identity_isderived()
  * - ::lyplg_type_identity_module()
  * - ::lyplg_type_make_implemented()
@@ -253,6 +255,33 @@
         struct ly_err_item **err);
 
 /**
+ * @brief Check that the value of a type is allowed based on its status.
+ *
+ * @param[in] ctx_node Context node (which references the value).
+ * @param[in] val_flags Flags fo the value.
+ * @param[in] format Format of the value.
+ * @param[in] prefix_data Prefix data of the value.
+ * @param[in] val_name Name of the value, only for logging.
+ * @param[out] err Pointer to store error information in case of failure.
+ * @return LY_ERR value.
+ */
+LY_ERR lyplg_type_check_status(const struct lysc_node *ctx_node, uint16_t val_flags, LY_VALUE_FORMAT format,
+        void *prefix_data, const char *val_name, struct ly_err_item **err);
+
+/**
+ * @brief Check that the lypath instance-identifier value is allowed based on the status of the nodes.
+ *
+ * @param[in] ctx_node Context node (which references the value).
+ * @param[in] path Path of the instance-identifier.
+ * @param[in] format Format of the value.
+ * @param[in] prefix_data Prefix data of the value.
+ * @param[out] err Pointer to store error information in case of failure.
+ * @return LY_ERR value.
+ */
+LY_ERR lyplg_type_lypath_check_status(const struct lysc_node *ctx_node, const struct ly_path *path,
+        LY_VALUE_FORMAT format, void *prefix_data, struct ly_err_item **err);
+
+/**
  * @brief Get the corresponding module for the identity value.
  *
  * Use only in implementations of ::lyplg_type_store_clb which provide all the necessary parameters for this function.
diff --git a/src/plugins_types/identityref.c b/src/plugins_types/identityref.c
index 3a6319c..65061ab 100644
--- a/src/plugins_types/identityref.c
+++ b/src/plugins_types/identityref.c
@@ -249,6 +249,10 @@
     ret = identityref_check_base(ident, type_ident, value, value_len, err);
     LY_CHECK_GOTO(ret, cleanup);
 
+    /* check status */
+    ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
+    LY_CHECK_GOTO(ret, cleanup);
+
     /* store value */
     storage->ident = ident;
 
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index 72f4e68..d958567 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -173,6 +173,10 @@
     /* store value */
     storage->target = path;
 
+    /* check status */
+    ret = lyplg_type_lypath_check_status(ctx_node, path, format, prefix_data, err);
+    LY_CHECK_GOTO(ret, cleanup);
+
     /* store canonical value */
     if (format == LY_VALUE_CANON) {
         if (options & LYPLG_TYPE_STORE_DYNAMIC) {
diff --git a/src/schema_compile.c b/src/schema_compile.c
index d824029..c2478e5 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -177,6 +177,13 @@
 }
 
 static void
+lysc_unres_must_free(struct lysc_unres_must *m)
+{
+    LY_ARRAY_FREE(m->local_mods);
+    free(m);
+}
+
+static void
 lysc_unres_dflt_free(const struct ly_ctx *ctx, struct lysc_unres_dflt *r)
 {
     assert(!r->dflt || !r->dflts);
@@ -820,7 +827,7 @@
 }
 
 /**
- * @brief Check when/must expressions of a node on a complete compiled schema tree.
+ * @brief Check when expressions of a node on a complete compiled schema tree.
  *
  * @param[in] ctx Compile context.
  * @param[in] node Node to check.
@@ -829,14 +836,12 @@
  * @return LY_ERR value
  */
 static LY_ERR
-lys_compile_unres_xpath(struct lysc_ctx *ctx, const struct lysc_node *node, struct lys_glob_unres *unres)
+lys_compile_unres_when(struct lysc_ctx *ctx, const struct lysc_node *node, struct lys_glob_unres *unres)
 {
     struct lyxp_set tmp_set;
     uint32_t i, opts;
     LY_ARRAY_COUNT_TYPE u;
-    ly_bool input_done = 0;
     struct lysc_when **whens = NULL;
-    struct lysc_must *musts = NULL;
     LY_ERR ret = LY_SUCCESS;
     const struct lys_module *mod;
 
@@ -846,8 +851,6 @@
     opts = LYXP_SCNODE_SCHEMA | ((node->flags & LYS_IS_OUTPUT) ? LYXP_SCNODE_OUTPUT : 0);
 
     whens = lysc_node_when(node);
-    musts = lysc_node_musts(node);
-
     LY_ARRAY_FOR(whens, u) {
         /* first check whether all the referenced modules are implemented */
         mod = NULL;
@@ -902,7 +905,40 @@
         lyxp_set_free_content(&tmp_set);
     }
 
-check_musts:
+cleanup:
+    lyxp_set_free_content(&tmp_set);
+    LOG_LOCBACK(1, 0, 0, 0);
+    return ret;
+}
+
+/**
+ * @brief Check must expressions of a node on a complete compiled schema tree.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Node to check.
+ * @param[in] local_mods Sized array of local modules for musts of @p node at the same index.
+ * @param[in,out] unres Global unres structure.
+ * @return LY_ERECOMPILE
+ * @return LY_ERR value
+ */
+static LY_ERR
+lys_compile_unres_must(struct lysc_ctx *ctx, const struct lysc_node *node, const struct lysp_module **local_mods,
+        struct lys_glob_unres *unres)
+{
+    struct lyxp_set tmp_set;
+    uint32_t i, opts;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysc_must *musts = NULL;
+    LY_ERR ret = LY_SUCCESS;
+    const struct lys_module *mod;
+    uint16_t flg;
+
+    LOG_LOCSET(node, NULL, NULL, NULL);
+
+    memset(&tmp_set, 0, sizeof tmp_set);
+    opts = LYXP_SCNODE_SCHEMA | ((node->flags & LYS_IS_OUTPUT) ? LYXP_SCNODE_OUTPUT : 0);
+
+    musts = lysc_node_musts(node);
     LY_ARRAY_FOR(musts, u) {
         /* first check whether all the referenced modules are implemented */
         mod = NULL;
@@ -930,7 +966,14 @@
             /* skip roots'n'stuff */
             if (tmp_set.val.scnodes[i].type == LYXP_NODE_ELEM) {
                 /* XPath expression cannot reference "lower" status than the node that has the definition */
-                ret = lysc_check_status(ctx, node->flags, node->module, node->name, tmp_set.val.scnodes[i].scnode->flags,
+                if (local_mods[u]->mod == node->module) {
+                    /* use flags of the context node since the definition is local */
+                    flg = node->flags;
+                } else {
+                    /* definition is foreign (deviation, refine), always current */
+                    flg = LYS_STATUS_CURR;
+                }
+                ret = lysc_check_status(ctx, flg, local_mods[u]->mod, node->name, tmp_set.val.scnodes[i].scnode->flags,
                         tmp_set.val.scnodes[i].scnode->module, tmp_set.val.scnodes[i].scnode->name);
                 LY_CHECK_GOTO(ret, cleanup);
             }
@@ -939,15 +982,6 @@
         lyxp_set_free_content(&tmp_set);
     }
 
-    if ((node->nodetype & (LYS_RPC | LYS_ACTION)) && !input_done) {
-        /* now check output musts */
-        input_done = 1;
-        whens = NULL;
-        musts = ((struct lysc_node_action *)node)->output.musts;
-        opts = LYXP_SCNODE_OUTPUT;
-        goto check_musts;
-    }
-
 cleanup:
     lyxp_set_free_content(&tmp_set);
     LOG_LOCBACK(1, 0, 0, 0);
@@ -960,17 +994,19 @@
  * @param[in] ctx Compile context.
  * @param[in] node Context node for the leafref.
  * @param[in] lref Leafref to check/resolve.
+ * @param[in] local_mod Local module for the leafref type.
  * @param[in,out] unres Global unres structure.
  * @return LY_ERECOMPILE if context recompilation is needed,
  * @return LY_ERR value.
  */
 static LY_ERR
 lys_compile_unres_leafref(struct lysc_ctx *ctx, const struct lysc_node *node, struct lysc_type_leafref *lref,
-        struct lys_glob_unres *unres)
+        const struct lysp_module *local_mod, struct lys_glob_unres *unres)
 {
     const struct lysc_node *target = NULL;
     struct ly_path *p;
     struct lysc_type *type;
+    uint16_t flg;
 
     assert(node->nodetype & (LYS_LEAF | LYS_LEAFLIST));
 
@@ -996,7 +1032,14 @@
     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)) {
+    if (node->module == local_mod->mod) {
+        /* use flags of the context node since the definition is local */
+        flg = node->flags;
+    } else {
+        /* definition is foreign (deviation), always current */
+        flg = LYS_STATUS_CURR;
+    }
+    if (lysc_check_status(ctx, flg, local_mod->mod, node->name, target->flags, target->module, target->name)) {
         return LY_EVALID;
     }
     ctx->path_len = 1;
@@ -1250,41 +1293,42 @@
      * point to the starting leafref type). The second round stores the first non-leafref type for later data validation.
      * Also do the same check for set of the disabled leafrefs, but without the second round. */
     while (ds_unres->disabled_leafrefs.count) {
-        node = ds_unres->disabled_leafrefs.objs[ds_unres->disabled_leafrefs.count - 1];
-        cctx.cur_mod = node->module;
-        cctx.pmod = node->module->parsed;
-        LOG_LOCSET(node, NULL, NULL, NULL);
+        struct lysc_unres_leafref *l = ds_unres->disabled_leafrefs.objs[ds_unres->disabled_leafrefs.count - 1];
+        cctx.cur_mod = l->node->module;
+        cctx.pmod = l->node->module->parsed;
+        LOG_LOCSET(l->node, NULL, NULL, NULL);
 
         v = 0;
-        while ((ret == LY_SUCCESS) && (lref = lys_type_leafref_next(node, &v))) {
-            ret = lys_compile_unres_leafref(&cctx, node, lref, unres);
+        while ((ret == LY_SUCCESS) && (lref = lys_type_leafref_next(l->node, &v))) {
+            ret = lys_compile_unres_leafref(&cctx, l->node, lref, l->local_mod, unres);
         }
 
         LOG_LOCBACK(1, 0, 0, 0);
         LY_CHECK_RET(ret);
+        free(l);
         ly_set_rm_index(&ds_unres->disabled_leafrefs, ds_unres->disabled_leafrefs.count - 1, NULL);
     }
 
     for (i = processed_leafrefs; i < ds_unres->leafrefs.count; ++i) {
-        node = ds_unres->leafrefs.objs[i];
-        cctx.cur_mod = node->module;
-        cctx.pmod = node->module->parsed;
-        LOG_LOCSET(node, NULL, NULL, NULL);
+        struct lysc_unres_leafref *l = ds_unres->leafrefs.objs[i];
+        cctx.cur_mod = l->node->module;
+        cctx.pmod = l->node->module->parsed;
+        LOG_LOCSET(l->node, NULL, NULL, NULL);
 
         v = 0;
-        while ((ret == LY_SUCCESS) && (lref = lys_type_leafref_next(node, &v))) {
-            ret = lys_compile_unres_leafref(&cctx, node, lref, unres);
+        while ((ret == LY_SUCCESS) && (lref = lys_type_leafref_next(l->node, &v))) {
+            ret = lys_compile_unres_leafref(&cctx, l->node, lref, l->local_mod, unres);
         }
 
         LOG_LOCBACK(1, 0, 0, 0);
         LY_CHECK_RET(ret);
     }
     for (i = processed_leafrefs; i < ds_unres->leafrefs.count; ++i) {
-        node = ds_unres->leafrefs.objs[i];
+        struct lysc_unres_leafref *l = ds_unres->leafrefs.objs[i];
 
         /* store pointer to the real type */
         v = 0;
-        while ((lref = lys_type_leafref_next(node, &v))) {
+        while ((lref = lys_type_leafref_next(l->node, &v))) {
             for (typeiter = lref->realtype;
                     typeiter->basetype == LY_TYPE_LEAFREF;
                     typeiter = ((struct lysc_type_leafref *)typeiter)->realtype) {}
@@ -1297,18 +1341,33 @@
         processed_leafrefs++;
     }
 
-    /* check xpath */
-    while (ds_unres->xpath.count) {
-        node = ds_unres->xpath.objs[ds_unres->xpath.count - 1];
+    /* check when */
+    while (ds_unres->whens.count) {
+        node = ds_unres->whens.objs[ds_unres->whens.count - 1];
         cctx.cur_mod = node->module;
         cctx.pmod = node->module->parsed;
 
         LOG_LOCSET(node, NULL, NULL, NULL);
-        ret = lys_compile_unres_xpath(&cctx, node, unres);
+        ret = lys_compile_unres_when(&cctx, node, unres);
         LOG_LOCBACK(1, 0, 0, 0);
         LY_CHECK_RET(ret);
 
-        ly_set_rm_index(&ds_unres->xpath, ds_unres->xpath.count - 1, NULL);
+        ly_set_rm_index(&ds_unres->whens, ds_unres->whens.count - 1, NULL);
+    }
+
+    /* check must */
+    while (ds_unres->musts.count) {
+        struct lysc_unres_must *m = ds_unres->musts.objs[ds_unres->musts.count - 1];
+        cctx.cur_mod = m->node->module;
+        cctx.pmod = m->node->module->parsed;
+
+        LOG_LOCSET(m->node, NULL, NULL, NULL);
+        ret = lys_compile_unres_must(&cctx, m->node, m->local_mods, unres);
+        LOG_LOCBACK(1, 0, 0, 0);
+        LY_CHECK_RET(ret);
+
+        lysc_unres_must_free(m);
+        ly_set_rm_index(&ds_unres->musts, ds_unres->musts.count - 1, NULL);
     }
 
     /* finish incomplete default values compilation */
@@ -1332,7 +1391,7 @@
 
     /* some unres items may have been added */
     if ((processed_leafrefs != ds_unres->leafrefs.count) || ds_unres->disabled_leafrefs.count ||
-            ds_unres->xpath.count || ds_unres->dflts.count) {
+            ds_unres->whens.count || ds_unres->musts.count || ds_unres->dflts.count) {
         goto resolve_all;
     }
 
@@ -1351,22 +1410,22 @@
 
     /* also check if the leafref target has not been disabled */
     for (i = 0; i < ds_unres->leafrefs.count; ++i) {
-        node = ds_unres->leafrefs.objs[i];
-        cctx.cur_mod = node->module;
-        cctx.pmod = node->module->parsed;
+        struct lysc_unres_leafref *l = ds_unres->leafrefs.objs[ds_unres->leafrefs.count - 1];
+        cctx.cur_mod = l->node->module;
+        cctx.pmod = l->node->module->parsed;
 
         v = 0;
-        while ((lref = lys_type_leafref_next(node, &v))) {
-            ret = ly_path_compile_leafref(cctx.ctx, node, NULL, lref->path,
-                    (node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
+        while ((lref = lys_type_leafref_next(l->node, &v))) {
+            ret = ly_path_compile_leafref(cctx.ctx, l->node, NULL, lref->path,
+                    (l->node->flags & LYS_IS_OUTPUT) ? LY_PATH_OPER_OUTPUT : LY_PATH_OPER_INPUT, LY_PATH_TARGET_MANY,
                     LY_VALUE_SCHEMA_RESOLVED, lref->prefixes, &path);
-            ly_path_free(node->module->ctx, path);
+            ly_path_free(l->node->module->ctx, path);
 
             assert(ret != LY_ERECOMPILE);
             if (ret) {
-                LOG_LOCSET(node, NULL, NULL, NULL);
+                LOG_LOCSET(l->node, NULL, NULL, NULL);
                 LOGVAL(ctx, LYVE_REFERENCE, "Target of leafref \"%s\" cannot be referenced because it is disabled.",
-                        node->name);
+                        l->node->name);
                 LOG_LOCBACK(1, 0, 0, 0);
                 return LY_EVALID;
             }
@@ -1387,13 +1446,17 @@
 {
     uint32_t i;
 
+    ly_set_erase(&unres->ds_unres.whens, NULL);
+    for (i = 0; i < unres->ds_unres.musts.count; ++i) {
+        lysc_unres_must_free(unres->ds_unres.musts.objs[i]);
+    }
+    ly_set_erase(&unres->ds_unres.musts, NULL);
+    ly_set_erase(&unres->ds_unres.leafrefs, free);
     for (i = 0; i < unres->ds_unres.dflts.count; ++i) {
         lysc_unres_dflt_free(ctx, unres->ds_unres.dflts.objs[i]);
     }
     ly_set_erase(&unres->ds_unres.dflts, NULL);
-    ly_set_erase(&unres->ds_unres.xpath, NULL);
-    ly_set_erase(&unres->ds_unres.leafrefs, NULL);
-    ly_set_erase(&unres->ds_unres.disabled_leafrefs, NULL);
+    ly_set_erase(&unres->ds_unres.disabled_leafrefs, free);
     ly_set_erase(&unres->ds_unres.disabled, NULL);
 }
 
diff --git a/src/schema_compile.h b/src/schema_compile.h
index 9c2e615..746b326 100644
--- a/src/schema_compile.h
+++ b/src/schema_compile.h
@@ -61,7 +61,8 @@
  * so their resolution can only be performed after the whole dep set compilation is done.
  */
 struct lys_depset_unres {
-    struct ly_set xpath;                /**< when/must to check */
+    struct ly_set whens;                /**< nodes with when to check */
+    struct ly_set musts;                /**< set of musts to check */
     struct ly_set leafrefs;             /**< to validate target of leafrefs */
     struct ly_set dflts;                /**< set of incomplete default values */
     struct ly_set disabled;             /**< set of compiled nodes whose if-feature(s) was not satisfied (stored ::lysc_node *) */
@@ -81,6 +82,22 @@
 };
 
 /**
+ * @brief Structure for storing schema nodes with must expressions and local module for each of them.
+ */
+struct lysc_unres_must {
+    struct lysc_node *node;     /**< node with the must expression(s) */
+    const struct lysp_module **local_mods;  /**< sized array of local modules for must(s) */
+};
+
+/**
+ * @brief Structure for storing leafref node and its local module.
+ */
+struct lysc_unres_leafref {
+    struct lysc_node *node;     /**< leaf/leaf-list node with leafref type */
+    const struct lysp_module *local_mod;    /**< local module of the leafref type */
+};
+
+/**
  * @brief Structure for remembering default values of leaves and leaf-lists. They are resolved at schema compilation
  * end when the whole schema tree is available.
  */
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 9642efb..74444ab 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -53,6 +53,105 @@
 }
 
 /**
+ * @brief Add a node with must(s) to unres.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Compiled node with must(s).
+ * @param[in] pnode Parsed ndoe with must(s).
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lysc_unres_must_add(struct lysc_ctx *ctx, struct lysc_node *node, struct lysp_node *pnode)
+{
+    struct lysc_unres_must *m = NULL;
+    LY_ARRAY_COUNT_TYPE u;
+    struct lysc_must *musts;
+    struct lysp_restr *pmusts;
+    LY_ERR ret;
+
+    /* do not check must(s) in a grouping */
+    if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
+        return LY_SUCCESS;
+    }
+
+    musts = lysc_node_musts(node);
+    pmusts = lysp_node_musts(pnode);
+    assert(LY_ARRAY_COUNT(musts) == LY_ARRAY_COUNT(pmusts));
+
+    if (!musts) {
+        /* no must */
+        return LY_SUCCESS;
+    }
+
+    /* add new unres must */
+    m = calloc(1, sizeof *m);
+    LY_CHECK_ERR_GOTO(!m, ret = LY_EMEM, error);
+    m->node = node;
+
+    /* add must local modules */
+    LY_ARRAY_CREATE_GOTO(ctx->ctx, m->local_mods, LY_ARRAY_COUNT(pmusts), ret, error);
+    LY_ARRAY_FOR(pmusts, u) {
+        m->local_mods[u] = pmusts[u].arg.mod;
+        LY_ARRAY_INCREMENT(m->local_mods);
+    }
+
+    LY_CHECK_ERR_GOTO(ly_set_add(&ctx->unres->musts, m, 1, NULL), ret = LY_EMEM, error);
+
+    return LY_SUCCESS;
+
+error:
+    if (m) {
+        LY_ARRAY_FREE(m->local_mods);
+        free(m);
+    }
+    LOGMEM(ctx->ctx);
+    return ret;
+}
+
+static LY_ERR
+lysc_unres_leafref_add(struct lysc_ctx *ctx, struct lysc_node_leaf *leaf, const struct lysp_module *local_mod)
+{
+    struct lysc_unres_leafref *l = NULL;
+    struct ly_set *leafrefs_set;
+    LY_ARRAY_COUNT_TYPE u;
+    int is_lref = 0;
+
+    if (ctx->compile_opts & LYS_COMPILE_GROUPING) {
+        /* do not check leafrefs in groupings */
+        return LY_SUCCESS;
+    }
+
+    /* use special set for disabled leafrefs */
+    leafrefs_set = ctx->compile_opts & LYS_COMPILE_DISABLED ? &ctx->unres->disabled_leafrefs : &ctx->unres->leafrefs;
+
+    if (leaf->type->basetype == LY_TYPE_LEAFREF) {
+        /* leafref */
+        is_lref = 1;
+    } else if (leaf->type->basetype == LY_TYPE_UNION) {
+        /* union with leafrefs */
+        LY_ARRAY_FOR(((struct lysc_type_union *)leaf->type)->types, u) {
+            if (((struct lysc_type_union *)leaf->type)->types[u]->basetype == LY_TYPE_LEAFREF) {
+                is_lref = 1;
+                break;
+            }
+        }
+    }
+
+    if (is_lref) {
+        /* add new unresolved leafref node */
+        l = calloc(1, sizeof *l);
+        LY_CHECK_ERR_RET(!l, LOGMEM(ctx->ctx), LY_EMEM);
+
+        l->node = &leaf->node;
+        l->local_mod = local_mod;
+
+        LY_CHECK_ERR_RET(ly_set_add(leafrefs_set, l, 1, NULL), free(l); LOGMEM(ctx->ctx), LY_EMEM);
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Add/replace a leaf default value in unres.
  * Can also be used for a single leaf-list default value.
  *
@@ -337,7 +436,7 @@
     if (!(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
         /* do not check "when" semantics in a grouping, but repeat the check for different node because
          * of dummy node check */
-        LY_CHECK_RET(ly_set_add(&ctx->unres->xpath, node, 0, NULL));
+        LY_CHECK_RET(ly_set_add(&ctx->unres->whens, node, 0, NULL));
     }
 
     return LY_SUCCESS;
@@ -2567,6 +2666,10 @@
     lysc_update_path(ctx, NULL, NULL);
     LY_CHECK_GOTO(ret, done);
 
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, &action->input.node, &input->node);
+    LY_CHECK_GOTO(ret, done);
+
     /* output */
     lysc_update_path(ctx, action->module, "output");
     if (action_p->output.nodetype == LYS_UNKNOWN) {
@@ -2578,11 +2681,9 @@
     lysc_update_path(ctx, NULL, NULL);
     LY_CHECK_GOTO(ret, done);
 
-    /* do not check "must" semantics in a grouping */
-    if ((action->input.musts || action->output.musts) && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        ret = ly_set_add(&ctx->unres->xpath, action, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, &action->output.node, &output->node);
+    LY_CHECK_GOTO(ret, done);
 
 done:
     return ret;
@@ -2605,11 +2706,10 @@
     struct lysp_node *child_p;
 
     COMPILE_ARRAY_GOTO(ctx, notif_p->musts, notif->musts, lys_compile_must, ret, done);
-    if (notif_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        ret = ly_set_add(&ctx->unres->xpath, notif, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
 
     LY_LIST_FOR(notif_p->child, child_p) {
         ret = lys_compile_node(ctx, child_p, node, 0, NULL);
@@ -2652,11 +2752,10 @@
     }
 
     COMPILE_ARRAY_GOTO(ctx, cont_p->musts, cont->musts, lys_compile_must, ret, done);
-    if (cont_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        ret = ly_set_add(&ctx->unres->xpath, cont, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
 
     LY_LIST_FOR((struct lysp_node *)cont_p->actions, child_p) {
         ret = lys_compile_node(ctx, child_p, node, 0, NULL);
@@ -2684,7 +2783,6 @@
         struct lysc_node_leaf *leaf)
 {
     struct lysp_qname *dflt;
-    struct ly_set *leafrefs_set;
 
     LY_CHECK_RET(lys_compile_type(ctx, context_node, leaf->flags, leaf->name, type_p, &leaf->type,
             leaf->units ? NULL : &leaf->units, &dflt));
@@ -2694,19 +2792,10 @@
         LY_CHECK_RET(lysc_unres_leaf_dflt_add(ctx, leaf, dflt));
     }
 
-    leafrefs_set = ctx->compile_opts & LYS_COMPILE_DISABLED ? &ctx->unres->disabled_leafrefs : &ctx->unres->leafrefs;
-    if ((leaf->type->basetype == LY_TYPE_LEAFREF) && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* store to validate the path in the current context at the end of schema compiling when all the nodes are present */
-        LY_CHECK_RET(ly_set_add(leafrefs_set, leaf, 0, NULL));
-    } else if ((leaf->type->basetype == LY_TYPE_UNION) && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        LY_ARRAY_COUNT_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_CHECK_RET(ly_set_add(leafrefs_set, leaf, 0, NULL));
-            }
-        }
-    } else if (leaf->type->basetype == LY_TYPE_EMPTY) {
+    /* store leafref(s) to be resolved */
+    LY_CHECK_RET(lysc_unres_leafref_add(ctx, leaf, type_p->pmod));
+
+    if (leaf->type->basetype == LY_TYPE_EMPTY) {
         if ((leaf->nodetype == LYS_LEAFLIST) && (ctx->pmod->version < LYS_VERSION_1_1)) {
             LOGVAL(ctx->ctx, LYVE_SEMANTICS, "Leaf-list of type \"empty\" is allowed only in YANG 1.1 modules.");
             return LY_EVALID;
@@ -2732,11 +2821,11 @@
     LY_ERR ret = LY_SUCCESS;
 
     COMPILE_ARRAY_GOTO(ctx, leaf_p->musts, leaf->musts, lys_compile_must, ret, done);
-    if (leaf_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        ret = ly_set_add(&ctx->unres->xpath, leaf, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
+
     if (leaf_p->units) {
         LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, leaf_p->units, 0, &leaf->units), done);
         leaf->flags |= LYS_SET_UNITS;
@@ -2778,11 +2867,11 @@
     LY_ERR ret = LY_SUCCESS;
 
     COMPILE_ARRAY_GOTO(ctx, llist_p->musts, llist->musts, lys_compile_must, ret, done);
-    if (llist_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        ret = ly_set_add(&ctx->unres->xpath, llist, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
+
     if (llist_p->units) {
         LY_CHECK_GOTO(ret = lydict_insert(ctx->ctx, llist_p->units, 0, &llist->units), done);
         llist->flags |= LYS_SET_UNITS;
@@ -3044,7 +3133,7 @@
             }
 
             /* check status */
-            LY_CHECK_RET(lysc_check_status(ctx, list->flags, list->module, list->name,
+            LY_CHECK_RET(lysc_check_status(ctx, list->flags, uniques[v].mod->mod, list->name,
                     (*key)->flags, (*key)->module, (*key)->name));
 
             /* mark leaf as unique */
@@ -3089,10 +3178,10 @@
     }
 
     COMPILE_ARRAY_GOTO(ctx, list_p->musts, list->musts, lys_compile_must, ret, done);
-    if (list_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        LY_CHECK_RET(ly_set_add(&ctx->unres->xpath, list, 0, NULL));
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
 
     /* keys */
     if ((list->flags & LYS_CONFIG_W) && (!list_p->key || !list_p->key[0])) {
@@ -3400,11 +3489,10 @@
     LY_ERR ret = LY_SUCCESS;
 
     COMPILE_ARRAY_GOTO(ctx, any_p->musts, any->musts, lys_compile_must, ret, done);
-    if (any_p->musts && !(ctx->compile_opts & LYS_COMPILE_GROUPING)) {
-        /* do not check "must" semantics in a grouping */
-        ret = ly_set_add(&ctx->unres->xpath, any, 0, NULL);
-        LY_CHECK_GOTO(ret, done);
-    }
+
+    /* add must(s) to unres */
+    ret = lysc_unres_must_add(ctx, node, pnode);
+    LY_CHECK_GOTO(ret, done);
 
     if (any->flags & LYS_CONFIG_W) {
         LOGVRB("Use of %s to define configuration data is not recommended. %s",
diff --git a/src/tree_schema.c b/src/tree_schema.c
index a117e62..5f27502 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1161,7 +1161,8 @@
     ly_set_erase(&unres->implementing, NULL);
     ly_set_erase(&unres->creating, NULL);
 
-    assert(!unres->ds_unres.xpath.count);
+    assert(!unres->ds_unres.whens.count);
+    assert(!unres->ds_unres.musts.count);
     assert(!unres->ds_unres.leafrefs.count);
     assert(!unres->ds_unres.disabled_leafrefs.count);
     assert(!unres->ds_unres.dflts.count);