Merge branch 'master' into devel
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c07a85..4322a00 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,12 +62,12 @@
 # set version of the project
 set(LIBYANG_MAJOR_VERSION 2)
 set(LIBYANG_MINOR_VERSION 0)
-set(LIBYANG_MICRO_VERSION 112)
+set(LIBYANG_MICRO_VERSION 126)
 set(LIBYANG_VERSION ${LIBYANG_MAJOR_VERSION}.${LIBYANG_MINOR_VERSION}.${LIBYANG_MICRO_VERSION})
 # set version of the library
 set(LIBYANG_MAJOR_SOVERSION 2)
 set(LIBYANG_MINOR_SOVERSION 13)
-set(LIBYANG_MICRO_SOVERSION 7)
+set(LIBYANG_MICRO_SOVERSION 19)
 set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
 set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})
 
diff --git a/src/common.h b/src/common.h
index 20b53b0..ebc142d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "compat.h"
 #include "context.h"
 #include "hash_table.h"
 #include "log.h"
@@ -59,8 +60,8 @@
  * Logger
  *****************************************************************************/
 
-extern volatile LY_LOG_LEVEL ly_ll;
-extern volatile uint32_t ly_log_opts;
+extern ATOMIC_T ly_ll;
+extern ATOMIC_T ly_log_opts;
 
 struct ly_log_location_s {
     uint64_t line;                   /**< One-time line value being reset after use - replaces whatever is in inputs */
@@ -220,6 +221,13 @@
 #define LY_CHECK_ARG_RET(CTX, ...) GETMACRO6(__VA_ARGS__, LY_CHECK_ARG_RET5, LY_CHECK_ARG_RET4, LY_CHECK_ARG_RET3, \
     LY_CHECK_ARG_RET2, LY_CHECK_ARG_RET1, DUMMY) (CTX, __VA_ARGS__)
 
+#define LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX2, RETVAL) if ((CTX1) && (CTX2) && ((CTX1) != (CTX2))) \
+    {LOGERR(CTX1, LY_EINVAL, "Different contexts mixed in a single function call."); return RETVAL;}
+#define LY_CHECK_CTX_EQUAL_RET3(CTX1, CTX2, CTX3, RETVAL) LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX2, RETVAL); \
+    LY_CHECK_CTX_EQUAL_RET2(CTX2, CTX3, RETVAL); LY_CHECK_CTX_EQUAL_RET2(CTX1, CTX3, RETVAL)
+#define LY_CHECK_CTX_EQUAL_RET(CTX, ...) GETMACRO3(__VA_ARGS__, LY_CHECK_CTX_EQUAL_RET3, LY_CHECK_CTX_EQUAL_RET2, \
+    DUMMY) (CTX, __VA_ARGS__)
+
 /* count sequence size for LY_VCODE_INCHILDSTMT validation error code */
 size_t LY_VCODE_INSTREXP_len(const char *str);
 /* default maximum characters to print in LY_VCODE_INCHILDSTMT */
diff --git a/src/config.h.in b/src/config.h.in
index 7f4257d..de9c40c 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -21,15 +21,15 @@
 /** plugins */
 #define LYPLG_SUFFIX "@CMAKE_SHARED_MODULE_SUFFIX@"
 #define LYPLG_SUFFIX_LEN (sizeof LYPLG_SUFFIX - 1)
-#define LYPLG_TYPE_DIR "@PLUGINS_DIR_EXTENSIONS@"
-#define LYPLG_EXT_DIR "@PLUGINS_DIR_TYPES@"
+#define LYPLG_TYPE_DIR "@PLUGINS_DIR_TYPES@"
+#define LYPLG_EXT_DIR "@PLUGINS_DIR_EXTENSIONS@"
 
 /** atomic compiler operations, to be able to use uint32_t */
 #define LY_ATOMIC_INC_BARRIER(var) __sync_fetch_and_add(&(var), 1)
 #define LY_ATOMIC_DEC_BARRIER(var) __sync_fetch_and_sub(&(var), 1)
 
 /** printf compiler attribute */
-#if (@CMAKE_C_COMPILER_ID@ == GNU) || (@CMAKE_C_COMPILER_ID@ == Clang)
+#ifdef __GNUC__
 # define _FORMAT_PRINTF(FORM, ARGS) __attribute__((format (printf, FORM, ARGS)))
 #else
 # define _FORMAT_PRINTF(FORM, ARGS)
diff --git a/src/context.h b/src/context.h
index a8aa29b..553892f 100644
--- a/src/context.h
+++ b/src/context.h
@@ -605,8 +605,8 @@
  * and free all structures internally used by libyang. If the caller uses
  * multiple contexts, the function should be called for each used context.
  *
- * All instance data are supposed to be freed before destroying the context.
- * Data models are destroyed automatically as part of ::ly_ctx_destroy() call.
+ * All instance data are supposed to be freed before destroying the context using ::lyd_free_all(), for example.
+ * Data models (schemas) are destroyed automatically as part of ::ly_ctx_destroy() call.
  *
  * Note that the data stored by user into the ::lysc_node.priv pointer are kept
  * untouched and the caller is responsible for freeing this private data.
diff --git a/src/log.c b/src/log.c
index a89e6ff..c023f65 100644
--- a/src/log.c
+++ b/src/log.c
@@ -33,12 +33,12 @@
 #include "tree_data.h"
 #include "tree_schema.h"
 
-volatile LY_LOG_LEVEL ly_ll = LY_LLWRN;
-volatile uint32_t ly_log_opts = LY_LOLOG | LY_LOSTORE_LAST;
+ATOMIC_T ly_ll = (uint_fast32_t)LY_LLWRN;
+ATOMIC_T ly_log_opts = (uint_fast32_t)(LY_LOLOG | LY_LOSTORE_LAST);
 static ly_log_clb log_clb;
-static volatile ly_bool path_flag = 1;
+static ATOMIC_T path_flag = 1;
 #ifndef NDEBUG
-volatile uint32_t ly_ldbg_groups = 0;
+ATOMIC_T ly_ldbg_groups = 0;
 #endif
 
 THREAD_LOCAL struct ly_log_location_s log_location = {0};
@@ -226,18 +226,18 @@
 API LY_LOG_LEVEL
 ly_log_level(LY_LOG_LEVEL level)
 {
-    LY_LOG_LEVEL prev = ly_ll;
+    LY_LOG_LEVEL prev = ATOMIC_LOAD_RELAXED(ly_ll);
 
-    ly_ll = level;
+    ATOMIC_STORE_RELAXED(ly_ll, level);
     return prev;
 }
 
 API uint32_t
 ly_log_options(uint32_t opts)
 {
-    uint32_t prev = ly_log_opts;
+    uint32_t prev = ATOMIC_LOAD_RELAXED(ly_log_opts);
 
-    ly_log_opts = opts;
+    ATOMIC_STORE_RELAXED(ly_log_opts, opts);
     return prev;
 }
 
@@ -245,9 +245,9 @@
 ly_log_dbg_groups(uint32_t dbg_groups)
 {
 #ifndef NDEBUG
-    uint32_t prev = ly_ldbg_groups;
+    uint32_t prev = ATOMIC_LOAD_RELAXED(ly_ldbg_groups);
 
-    ly_ldbg_groups = dbg_groups;
+    ATOMIC_STORE_RELAXED(ly_ldbg_groups, dbg_groups);
     return prev;
 #else
     (void)dbg_groups;
@@ -259,7 +259,7 @@
 ly_set_log_clb(ly_log_clb clb, ly_bool path)
 {
     log_clb = clb;
-    path_flag = path;
+    ATOMIC_STORE_RELAXED(path_flag, path);
 }
 
 API ly_log_clb
@@ -372,7 +372,7 @@
         } while (eitem->prev->next);
         /* last error was not found */
         assert(0);
-    } else if ((ly_log_opts & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
+    } else if ((ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE_LAST) == LY_LOSTORE_LAST) {
         /* overwrite last message */
         free(eitem->msg);
         free(eitem->path);
@@ -412,7 +412,7 @@
     char *msg = NULL;
     ly_bool free_strs;
 
-    if (level > ly_ll) {
+    if (level > ATOMIC_LOAD_RELAXED(ly_ll)) {
         /* do not print or store the message */
         free(path);
         return;
@@ -420,7 +420,7 @@
 
     if (no == LY_EMEM) {
         /* just print it, anything else would most likely fail anyway */
-        if (ly_log_opts & LY_LOLOG) {
+        if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
             if (log_clb) {
                 log_clb(level, LY_EMEM_MSG, path);
             } else {
@@ -438,7 +438,7 @@
     }
 
     /* store the error/warning (if we need to store errors internally, it does not matter what are the user log options) */
-    if ((level < LY_LLVRB) && ctx && (ly_log_opts & LY_LOSTORE)) {
+    if ((level < LY_LLVRB) && ctx && (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOSTORE)) {
         assert(format);
         if (vasprintf(&msg, format, args) == -1) {
             LOGMEM(ctx);
@@ -463,7 +463,7 @@
     }
 
     /* if we are only storing errors internally, never print the message (yet) */
-    if (ly_log_opts & LY_LOLOG) {
+    if (ATOMIC_LOAD_RELAXED(ly_log_opts) & LY_LOLOG) {
         if (log_clb) {
             log_clb(level, msg, path);
         } else {
@@ -489,7 +489,7 @@
     const char *str_group;
     va_list ap;
 
-    if (!(ly_ldbg_groups & group)) {
+    if (!(ATOMIC_LOAD_RELAXED(ly_ldbg_groups) & group)) {
         return;
     }
 
@@ -594,7 +594,7 @@
     va_list ap;
     char *path = NULL;
 
-    if (path_flag && ctx) {
+    if (ATOMIC_LOAD_RELAXED(path_flag) && ctx) {
         ly_vlog_build_path(ctx, &path);
     }
 
@@ -611,7 +611,7 @@
     char *plugin_msg;
     int ret;
 
-    if (ly_ll < level) {
+    if (ATOMIC_LOAD_RELAXED(ly_ll) < level) {
         return;
     }
     ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s", ext->def->plugin->id, format);
diff --git a/src/log.h b/src/log.h
index 7a12858..7c60cae 100644
--- a/src/log.h
+++ b/src/log.h
@@ -75,7 +75,7 @@
  * @{
  *
  * Publicly visible functions and values of the libyang logger. For more
- * information, see \ref howtoLogger.
+ * information, see @ref howtoLogger.
  */
 
 /**
@@ -84,11 +84,11 @@
  */
 typedef enum
 {
-    LY_LLERR = 0, /**< Print only error messages, default value. */
-    LY_LLWRN = 1, /**< Print error and warning messages. */
+    LY_LLERR = 0, /**< Print only error messages. */
+    LY_LLWRN = 1, /**< Print error and warning messages, default value. */
     LY_LLVRB = 2, /**< Besides errors and warnings, print some other verbose messages. */
-    LY_LLDBG = 3 /**< Print all messages including some development debug messages (be careful,
-     without subsequently calling ::ly_log_dbg_groups() no debug messages will be printed!). */
+    LY_LLDBG = 3  /**< Print all messages including some development debug messages (be careful,
+                       without subsequently calling ::ly_log_dbg_groups() no debug messages will be printed!). */
 } LY_LOG_LEVEL;
 
 /**
diff --git a/src/parser_json.c b/src/parser_json.c
index 4eca7d7..66e58ed 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1578,7 +1578,7 @@
 
 cleanup:
     /* there should be no unresolved types stored */
-    assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
+    assert(!(parse_opts & LYD_PARSE_ONLY) || !lydctx || (!lydctx->node_types.count && !lydctx->meta_types.count &&
             !lydctx->node_when.count));
 
     if (rc) {
diff --git a/src/parser_stmt.c b/src/parser_stmt.c
index 2875b75..4dfda0b 100644
--- a/src/parser_stmt.c
+++ b/src/parser_stmt.c
@@ -168,7 +168,7 @@
     /* allocate new pointer */
     LY_ARRAY_NEW_RET(PARSER_CTX(ctx), *qnames, item, LY_EMEM);
     LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &item->str));
-    item->mod = ctx->parsed_mod;
+    item->mod = PARSER_CUR_PMOD(ctx);
 
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
@@ -416,7 +416,7 @@
 {
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_STR_ARG, stmt->arg));
     LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &restr->arg.str));
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
@@ -844,7 +844,7 @@
     buf[0] = LYSP_RESTR_PATTERN_ACK; /* pattern's default regular-match flag */
     buf[arg_len + 1] = '\0'; /* terminating NULL byte */
     LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str));
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
@@ -898,7 +898,7 @@
 
     LY_CHECK_RET(lysp_stmt_validate_value(ctx, Y_PREF_IDENTIF_ARG, stmt->arg));
     LY_CHECK_RET(lydict_insert(PARSER_CTX(ctx), stmt->arg, 0, &type->name));
-    type->pmod = ctx->parsed_mod;
+    type->pmod = PARSER_CUR_PMOD(ctx);
 
     for (const struct lysp_stmt *child = stmt->child; child; child = child->next) {
         switch (child->kw) {
@@ -1005,7 +1005,7 @@
             break;
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &leaf->dflt.str, Y_STR_ARG, &leaf->exts));
-            leaf->dflt.mod = ctx->parsed_mod;
+            leaf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts));
@@ -1403,7 +1403,7 @@
         switch (child->kw) {
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &tpdf->dflt.str, Y_STR_ARG, &tpdf->exts));
-            tpdf->dflt.mod = ctx->parsed_mod;
+            tpdf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts));
@@ -2045,7 +2045,7 @@
             break;
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(lysp_stmt_text_field(ctx, child, 0, &choice->dflt.str, Y_PREF_IDENTIF_ARG, &choice->exts));
-            choice->dflt.mod = ctx->parsed_mod;
+            choice->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_ANYDATA:
             PARSER_CHECK_STMTVER2_RET(ctx, "anydata", "choice");
@@ -2306,9 +2306,15 @@
     LY_ERR ret = LY_SUCCESS;
     uint16_t flags;
     struct lys_parser_ctx pctx = {0};
+    struct ly_set pmods = {0};
+    void *objs;
 
+    /* local context */
     pctx.format = LYS_IN_YANG;
-    pctx.parsed_mod = ctx->pmod;
+    pctx.parsed_mods = &pmods;
+    objs = &ctx->pmod;
+    pmods.objs = objs;
+    pmods.count = 1;
 
     LOG_LOCSET(NULL, NULL, ctx->path, NULL);
 
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 79a1683..692064b 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -760,8 +760,7 @@
     } else if (*kw == LY_STMT_SYNTAX_LEFT_BRACE) {
         ctx->depth++;
         if (ctx->depth > LY_MAX_BLOCK_DEPTH) {
-            LOGERR(ctx->parsed_mod->mod->ctx, LY_EINVAL,
-                    "The maximum number of block nestings has been exceeded.");
+            LOGERR(PARSER_CTX(ctx), LY_EINVAL, "The maximum number of block nestings has been exceeded.");
             return LY_EINVAL;
         }
         goto success;
@@ -885,7 +884,7 @@
     }
 
     stmt->format = LY_VALUE_SCHEMA;
-    stmt->prefix_data = ctx->parsed_mod;
+    stmt->prefix_data = PARSER_CUR_PMOD(ctx);
     stmt->kw = kw;
 
     YANG_READ_SUBSTMT_FOR(ctx, child_kw, word, word_len, ret, return LY_SUCCESS, return ret) {
@@ -935,7 +934,7 @@
     /* store the rest of information */
     e->format = LY_VALUE_SCHEMA;
     e->parsed = NULL;
-    e->prefix_data = ctx->parsed_mod;
+    e->prefix_data = PARSER_CUR_PMOD(ctx);
     e->parent_stmt = insubstmt;
     e->parent_stmt_index = insubstmt_index;
 
@@ -1064,9 +1063,9 @@
 
     /* get value, it must match the main module */
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
-    if (ly_strncmp(ctx->parsed_mod->mod->name, word, word_len)) {
+    if (ly_strncmp(PARSER_CUR_PMOD(ctx)->mod->name, word, word_len)) {
         LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Submodule \"belongs-to\" value \"%.*s\" does not match its module name \"%s\".",
-                (int)word_len, word, ctx->parsed_mod->mod->name);
+                (int)word_len, word, PARSER_CUR_PMOD(ctx)->mod->name);
         free(buf);
         return LY_EVALID;
     }
@@ -1375,7 +1374,7 @@
     LY_CHECK_RET(get_argument(ctx, arg, NULL, &word, &buf, &word_len));
 
     INSERT_WORD_RET(ctx, buf, item->str, word, word_len);
-    item->mod = ctx->parsed_mod;
+    item->mod = PARSER_CUR_PMOD(ctx);
     YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
@@ -1509,7 +1508,7 @@
 
     CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
     INSERT_WORD_RET(ctx, buf, restr->arg.str, word, word_len);
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
     YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
@@ -2071,7 +2070,7 @@
     buf[0] = LYSP_RESTR_PATTERN_ACK; /* pattern's default regular-match flag */
     buf[word_len + 1] = '\0'; /* terminating NULL byte */
     LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str));
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
     YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
         switch (kw) {
@@ -2130,7 +2129,7 @@
     INSERT_WORD_RET(ctx, buf, type->name, word, word_len);
 
     /* set module */
-    type->pmod = ctx->parsed_mod;
+    type->pmod = PARSER_CUR_PMOD(ctx);
 
     YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
         switch (kw) {
@@ -2250,7 +2249,7 @@
             break;
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &leaf->dflt.str, Y_STR_ARG, &leaf->exts));
-            leaf->dflt.mod = ctx->parsed_mod;
+            leaf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &leaf->dsc, Y_STR_ARG, &leaf->exts));
@@ -2663,7 +2662,7 @@
         switch (kw) {
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &tpdf->dflt.str, Y_STR_ARG, &tpdf->exts));
-            tpdf->dflt.mod = ctx->parsed_mod;
+            tpdf->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &tpdf->dsc, Y_STR_ARG, &tpdf->exts));
@@ -3339,7 +3338,7 @@
         case LY_STMT_DEFAULT:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &choice->dflt.str, Y_PREF_IDENTIF_ARG,
                     &choice->exts));
-            choice->dflt.mod = ctx->parsed_mod;
+            choice->dflt.mod = PARSER_CUR_PMOD(ctx);
             break;
 
         case LY_STMT_ANYDATA:
@@ -3849,7 +3848,7 @@
                 return LY_EVALID;
             case LYS_DEV_REPLACE:
                 LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DEFAULT, 0, &d_rpl->dflt.str, Y_STR_ARG, &d->exts));
-                d_rpl->dflt.mod = ctx->parsed_mod;
+                d_rpl->dflt.mod = PARSER_CUR_PMOD(ctx);
                 break;
             default:
                 LY_CHECK_RET(parse_qnames(ctx, LY_STMT_DEFAULT, d_dflts, Y_STR_ARG, &d->exts));
@@ -4091,7 +4090,7 @@
             LY_CHECK_RET(parse_status(ctx, &ident->flags, &ident->exts));
             break;
         case LY_STMT_BASE:
-            if (ident->bases && (ctx->parsed_mod->version < LYS_VERSION_1_1)) {
+            if (ident->bases && (PARSER_CUR_PMOD(ctx)->version < LYS_VERSION_1_1)) {
                 LOGVAL_PARSER(ctx, LYVE_SYNTAX_YANG, "Identity can be derived from multiple base identities only in YANG 1.1 modules");
                 return LY_EVALID;
             }
@@ -4575,9 +4574,12 @@
 
     mod_p = calloc(1, sizeof *mod_p);
     LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ly_ctx); ret = LY_EMEM, cleanup);
-    mod_p->mod = main_ctx->parsed_mod->mod;
+    mod_p->mod = PARSER_CUR_PMOD(main_ctx)->mod;
     mod_p->parsing = 1;
-    (*context)->parsed_mod = (struct lysp_module *)mod_p;
+
+    /* use main context parsed mods adding the current one */
+    (*context)->parsed_mods = main_ctx->parsed_mods;
+    ly_set_add((*context)->parsed_mods, mod_p, 1, NULL);
 
     LOG_LOCINIT(NULL, NULL, NULL, in);
 
@@ -4639,13 +4641,14 @@
     *context = calloc(1, sizeof **context);
     LY_CHECK_ERR_RET(!(*context), LOGMEM(mod->ctx), LY_EMEM);
     (*context)->format = LYS_IN_YANG;
+    LY_CHECK_ERR_RET(ly_set_new(&(*context)->parsed_mods), free(*context); LOGMEM(mod->ctx), LY_EMEM);
     (*context)->in = in;
     (*context)->main_ctx = (struct lys_parser_ctx *)(*context);
 
     mod_p = calloc(1, sizeof *mod_p);
     LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(mod->ctx), cleanup);
     mod_p->mod = mod;
-    (*context)->parsed_mod = mod_p;
+    ly_set_add((*context)->parsed_mods, mod_p, 1, NULL);
 
     LOG_LOCINIT(NULL, NULL, NULL, in);
 
diff --git a/src/parser_yin.c b/src/parser_yin.c
index e5cb0bf..3ea8f0b 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -657,7 +657,7 @@
     saved_value[0] = LYSP_RESTR_PATTERN_ACK;
     saved_value[len + 1] = '\0';
     LY_CHECK_RET(lydict_insert_zc(ctx->xmlctx->ctx, saved_value, &restr->arg.str));
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
     type->flags |= LYS_SET_PATTERN;
 
     struct yin_subelement subelems[] = {
@@ -961,7 +961,7 @@
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, &restr->arg.str, Y_STR_ARG, restr_kw));
-    restr->arg.mod = ctx->parsed_mod;
+    restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
     return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr_kw, NULL, &restr->exts);
 }
@@ -1045,19 +1045,19 @@
             qnames = (struct lysp_qname **)subinfo->dest;
             LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
         }
-        qname->mod = ctx->parsed_mod;
+        qname->mod = PARSER_CUR_PMOD(ctx);
         return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_VALUE, Y_STR_ARG, exts);
     case LY_STMT_UNIQUE:
         assert(!(subinfo->flags & YIN_SUBELEM_UNIQUE));
         qnames = (struct lysp_qname **)subinfo->dest;
         LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
-        qname->mod = ctx->parsed_mod;
+        qname->mod = PARSER_CUR_PMOD(ctx);
         return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_TAG, Y_STR_ARG, exts);
     case LY_STMT_IF_FEATURE:
         assert(!(subinfo->flags & YIN_SUBELEM_UNIQUE));
         qnames = (struct lysp_qname **)subinfo->dest;
         LY_ARRAY_NEW_RET(ctx->xmlctx->ctx, *qnames, qname, LY_EMEM);
-        qname->mod = ctx->parsed_mod;
+        qname->mod = PARSER_CUR_PMOD(ctx);
         return yin_parse_simple_element(ctx, kw, &qname->str, YIN_ARG_NAME, Y_STR_ARG, exts);
     default:
         break;
@@ -1161,9 +1161,9 @@
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &belongsto, Y_IDENTIF_ARG, LY_STMT_BELONGS_TO));
-    if (ctx->parsed_mod->mod->name != belongsto) {
+    if (PARSER_CUR_PMOD(ctx)->mod->name != belongsto) {
         LOGVAL_PARSER(ctx, LYVE_SYNTAX_YIN, "Submodule \"belongs-to\" value \"%s\" does not match its module name \"%s\".",
-                belongsto, ctx->parsed_mod->mod->name);
+                belongsto, PARSER_CUR_PMOD(ctx)->mod->name);
         lydict_remove(ctx->xmlctx->ctx, belongsto);
         return LY_EVALID;
     }
@@ -1255,7 +1255,7 @@
         type = nested_type;
     }
 
-    type->pmod = ctx->parsed_mod;
+    type->pmod = PARSER_CUR_PMOD(ctx);
 
     struct yin_subelement subelems[] = {
         {LY_STMT_BASE, type, 0},
@@ -3333,7 +3333,7 @@
             }
             if (subelem->flags & YIN_SUBELEM_VER2) {
                 /* subelement is supported only in version 1.1 or higher */
-                if (ctx->parsed_mod->version < LYS_VERSION_1_1) {
+                if (PARSER_CUR_PMOD(ctx)->version < LYS_VERSION_1_1) {
                     LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
                     ret = LY_EVALID;
                     goto cleanup;
@@ -3435,9 +3435,9 @@
                 ret = yin_parse_import(ctx, (struct import_meta *)subelem->dest);
                 break;
             case LY_STMT_INCLUDE:
-                if ((current_element == LY_STMT_SUBMODULE) && (ctx->parsed_mod->version == LYS_VERSION_1_1)) {
+                if ((current_element == LY_STMT_SUBMODULE) && (PARSER_CUR_PMOD(ctx)->version == LYS_VERSION_1_1)) {
                     LOGWRN(PARSER_CTX(ctx), "YANG version 1.1 expects all includes in main module, includes in submodules (%s) are not necessary.",
-                            ((struct lysp_submodule *)(ctx->parsed_mod))->name);
+                            ((struct lysp_submodule *)PARSER_CUR_PMOD(ctx))->name);
                 }
                 ret = yin_parse_include(ctx, (struct include_meta *)subelem->dest);
                 break;
@@ -3717,9 +3717,12 @@
 
     mod_p = calloc(1, sizeof *mod_p);
     LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(ctx); ret = LY_EMEM, cleanup);
-    mod_p->mod = main_ctx->parsed_mod->mod;
+    mod_p->mod = PARSER_CUR_PMOD(main_ctx)->mod;
     mod_p->parsing = 1;
-    (*yin_ctx)->parsed_mod = (struct lysp_module *)mod_p;
+
+    /* use main context parsed mods adding the current one */
+    (*yin_ctx)->parsed_mods = main_ctx->parsed_mods;
+    ly_set_add((*yin_ctx)->parsed_mods, mod_p, 1, NULL);
 
     /* check submodule */
     kw = yin_match_keyword(*yin_ctx, (*yin_ctx)->xmlctx->name, (*yin_ctx)->xmlctx->name_len, (*yin_ctx)->xmlctx->prefix,
@@ -3774,13 +3777,14 @@
     *yin_ctx = calloc(1, sizeof **yin_ctx);
     LY_CHECK_ERR_RET(!(*yin_ctx), LOGMEM(mod->ctx), LY_EMEM);
     (*yin_ctx)->format = LYS_IN_YIN;
+    LY_CHECK_ERR_RET(ly_set_new(&(*yin_ctx)->parsed_mods), free(*yin_ctx); LOGMEM(mod->ctx), LY_EMEM);
     LY_CHECK_RET(lyxml_ctx_new(mod->ctx, in, &(*yin_ctx)->xmlctx));
     (*yin_ctx)->main_ctx = (struct lys_parser_ctx *)(*yin_ctx);
 
     mod_p = calloc(1, sizeof *mod_p);
     LY_CHECK_ERR_GOTO(!mod_p, LOGMEM(mod->ctx), cleanup);
     mod_p->mod = mod;
-    (*yin_ctx)->parsed_mod = mod_p;
+    ly_set_add((*yin_ctx)->parsed_mods, mod_p, 1, NULL);
 
     /* check module */
     kw = yin_match_keyword(*yin_ctx, (*yin_ctx)->xmlctx->name, (*yin_ctx)->xmlctx->name_len, (*yin_ctx)->xmlctx->prefix,
diff --git a/src/plugins_types/date_and_time.c b/src/plugins_types/date_and_time.c
index 6633622..62e304c 100644
--- a/src/plugins_types/date_and_time.c
+++ b/src/plugins_types/date_and_time.c
@@ -17,9 +17,11 @@
 #include "plugins_types.h"
 
 #include <ctype.h>
+#include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include "libyang.h"
 
@@ -33,6 +35,7 @@
  * | Size (B) | Mandatory | Type | Meaning |
  * | :------  | :-------: | :--: | :-----: |
  * | 8        | yes | `time_t *` | UNIX timestamp |
+ * | 1        | no | `int8_t *` | flag whether the value is in the special -00:00 unknown timezone or not |
  * | string length | no | `char *` | string with the fraction digits of a second |
  */
 
@@ -50,6 +53,7 @@
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type_str *type_dat = (struct lysc_type_str *)type;
     struct lyd_value_date_and_time *val;
+    struct tm tm;
     uint32_t i;
     char c;
 
@@ -66,7 +70,7 @@
                     "(expected at least 8).", value_len);
             goto cleanup;
         }
-        for (i = 8; i < value_len; ++i) {
+        for (i = 9; i < value_len; ++i) {
             c = ((char *)value)[i];
             if (!isdigit(c)) {
                 ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB date-and-time character '%c' "
@@ -79,11 +83,16 @@
         memcpy(&val->time, value, sizeof val->time);
 
         /* store fractions of second */
-        if (value_len > 8) {
-            val->fractions_s = strndup(((char *)value) + 8, value_len - 8);
+        if (value_len > 9) {
+            val->fractions_s = strndup(((char *)value) + 9, value_len - 9);
             LY_CHECK_ERR_GOTO(!val->fractions_s, ret = LY_EMEM, cleanup);
         }
 
+        /* store unknown timezone */
+        if (value_len > 8) {
+            val->unknown_tz = *(((int8_t *)value) + 8) ? 1 : 0;
+        }
+
         /* success */
         goto cleanup;
     }
@@ -106,6 +115,28 @@
     ret = ly_time_str2time(value, &val->time, &val->fractions_s);
     LY_CHECK_GOTO(ret, cleanup);
 
+    if (!strncmp(((char *)value + value_len) - 6, "-00:00", 6)) {
+        /* unknown timezone, move the timestamp to UTC */
+        tzset();
+        val->time += timezone;
+        val->unknown_tz = 1;
+
+        if (daylight) {
+            /* DST may apply, adjust accordingly */
+            if (!localtime_r(&val->time, &tm)) {
+                ret = ly_err_new(err, LY_ESYS, LYVE_DATA, NULL, NULL, "localtime_r() call failed (%s).", strerror(errno));
+                goto cleanup;
+            } else if (tm.tm_isdst < 0) {
+                ret = ly_err_new(err, LY_EINT, LYVE_DATA, NULL, NULL, "Failed to get DST information.");
+                goto cleanup;
+            }
+            if (tm.tm_isdst) {
+                /* move an hour back */
+                val->time -= 3600;
+            }
+        }
+    }
+
     if (format == LY_VALUE_CANON) {
         /* store canonical value */
         if (options & LYPLG_TYPE_STORE_DYNAMIC) {
@@ -144,8 +175,8 @@
     LYD_VALUE_GET(val1, v1);
     LYD_VALUE_GET(val2, v2);
 
-    /* compare timestamp */
-    if (v1->time != v2->time) {
+    /* compare timestamp and unknown tz */
+    if ((v1->time != v2->time) || (v1->unknown_tz != v2->unknown_tz)) {
         return LY_ENOT;
     }
 
@@ -170,16 +201,19 @@
     LYD_VALUE_GET(value, val);
 
     if (format == LY_VALUE_LYB) {
-        if (val->fractions_s) {
-            ret = malloc(8 + strlen(val->fractions_s));
+        if (val->unknown_tz || val->fractions_s) {
+            ret = malloc(8 + 1 + (val->fractions_s ? strlen(val->fractions_s) : 0));
             LY_CHECK_ERR_RET(!ret, LOGMEM(ctx), NULL);
 
             *dynamic = 1;
             if (value_len) {
-                *value_len = 8 + strlen(val->fractions_s);
+                *value_len = 8 + 1 + (val->fractions_s ? strlen(val->fractions_s) : 0);
             }
             memcpy(ret, &val->time, sizeof val->time);
-            memcpy(ret + 8, val->fractions_s, strlen(val->fractions_s));
+            memcpy(ret + 8, &val->unknown_tz, sizeof val->unknown_tz);
+            if (val->fractions_s) {
+                memcpy(ret + 9, val->fractions_s, strlen(val->fractions_s));
+            }
         } else {
             *dynamic = 0;
             if (value_len) {
@@ -197,6 +231,11 @@
             return NULL;
         }
 
+        if (val->unknown_tz) {
+            /* date and time is correct, fix only the timezone */
+            strcpy((ret + strlen(ret)) - 6, "-00:00");
+        }
+
         /* store it */
         if (lydict_insert_zc(ctx, ret, (const char **)&value->_canonical)) {
             LOGMEM(ctx);
@@ -235,8 +274,9 @@
 
     LYD_VALUE_GET(original, orig_val);
 
-    /* copy timestamp */
+    /* copy timestamp and unknown tz */
     dup_val->time = orig_val->time;
+    dup_val->unknown_tz = orig_val->unknown_tz;
 
     /* duplicate second fractions */
     if (orig_val->fractions_s) {
diff --git a/src/printer_json.c b/src/printer_json.c
index 3b45a6c..6b2ee02 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -35,12 +35,13 @@
  */
 struct jsonpr_ctx {
     struct ly_out *out;         /**< output specification */
+    const struct lyd_node *root;    /**< root node of the subtree being printed */
     uint16_t level;             /**< current indentation level: 0 - no formatting, >= 1 indentation levels */
     uint32_t options;           /**< [Data printer flags](@ref dataprinterflags) */
     const struct ly_ctx *ctx;   /**< libyang context */
 
     uint16_t level_printed;     /* level where some data were already printed */
-    struct ly_set open; /* currently open array(s) */
+    struct ly_set open;         /* currently open array(s) */
     const struct lyd_node *print_sibling_metadata;
 };
 
@@ -659,6 +660,34 @@
 }
 
 /**
+ * @brief Check whether a node is the last printed instance of a (leaf-)list.
+ *
+ * @param[in] ctx JSON printer context.
+ * @param[in] node Last printed node.
+ * @return Whether it is the last printed instance or not.
+ */
+static ly_bool
+json_print_array_is_last_inst(struct jsonpr_ctx *ctx, const struct lyd_node *node)
+{
+    if (!is_open_array(ctx, node)) {
+        /* no array open */
+        return 0;
+    }
+
+    if ((ctx->root == node) && !(ctx->options & LYD_PRINT_WITHSIBLINGS)) {
+        /* the only printed instance */
+        return 1;
+    }
+
+    if (!node->next || (node->next->schema != node->schema)) {
+        /* last instance */
+        return 1;
+    }
+
+    return 0;
+}
+
+/**
  * @brief Print single leaf-list or list instance.
  *
  * In case of list, metadata are printed inside the list object. For the leaf-list,
@@ -700,7 +729,7 @@
         }
     }
 
-    if (is_open_array(ctx, node) && (!node->next || (node->next->schema != node->schema))) {
+    if (json_print_array_is_last_inst(ctx, node)) {
         json_print_array_close(ctx);
     }
 
@@ -825,7 +854,7 @@
 json_print_node(struct jsonpr_ctx *ctx, const struct lyd_node *node)
 {
     if (!ly_should_print(node, ctx->options)) {
-        if (is_open_array(ctx, node) && (!node->next || (node->next->schema != node->schema))) {
+        if (json_print_array_is_last_inst(ctx, node)) {
             json_print_array_close(ctx);
         }
         return LY_SUCCESS;
@@ -892,6 +921,7 @@
 
     /* content */
     LY_LIST_FOR(root, node) {
+        ctx.root = node;
         LY_CHECK_RET(json_print_node(&ctx, node));
         if (!(options & LYD_PRINT_WITHSIBLINGS)) {
             break;
diff --git a/src/printer_yin.c b/src/printer_yin.c
index 93fd271..8883b68 100644
--- a/src/printer_yin.c
+++ b/src/printer_yin.c
@@ -377,12 +377,11 @@
 {
     int8_t inner_flag = 0;
 
-    (void)flag;
-
     if (!when) {
         return;
     }
 
+    ypr_close_parent(ctx, flag);
     ly_print_(ctx->out, "%*s<when condition=\"", INDENT);
     lyxml_dump_text(ctx->out, when->cond, 1);
     ly_print_(ctx->out, "\"");
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 5b52a19..179d3c0 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -1445,7 +1445,8 @@
     }
 
     /* remove disabled enums/bits */
-    for (i = 0; i < ds_unres->disabled_bitenums.count; ++i) {
+    while (ds_unres->disabled_bitenums.count) {
+        i = ds_unres->disabled_bitenums.count - 1;
         node = ds_unres->disabled_bitenums.objs[i];
         cctx.cur_mod = node->module;
         cctx.pmod = node->module->parsed;
diff --git a/src/tree_data.c b/src/tree_data.c
index dae9816..c05136e 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -871,9 +871,10 @@
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
-    struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -941,12 +942,13 @@
 {
     struct lyd_node *ret = NULL, *key;
     const struct lysc_node *schema, *key_s;
-    struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
     const void *key_val;
     uint32_t key_len;
     LY_ERR rc = LY_SUCCESS;
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -1085,9 +1087,10 @@
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
-    struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -1141,6 +1144,7 @@
     const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -1216,9 +1220,10 @@
 {
     struct lyd_node *ret = NULL;
     const struct lysc_node *schema;
-    struct ly_ctx *ctx = parent ? parent->schema->module->ctx : (module ? module->ctx : NULL);
+    const struct ly_ctx *ctx = parent ? LYD_CTX(parent) : (module ? module->ctx : NULL);
 
     LY_CHECK_ARG_RET(ctx, parent || module, parent || node, name, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
 
     if (!module) {
         module = parent->schema->module;
@@ -1273,6 +1278,7 @@
     size_t pref_len, name_len;
 
     LY_CHECK_ARG_RET(ctx, ctx || parent, name, module || strchr(name, ':'), parent || meta, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, module ? module->ctx : NULL, LY_EINVAL);
     if (!ctx) {
         ctx = LYD_CTX(parent);
     }
@@ -1314,6 +1320,7 @@
     const struct lys_module *mod;
 
     LY_CHECK_ARG_RET(NULL, ctx, attr, parent || meta, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
 
     if (parent && !parent->schema) {
         LOGERR(ctx, LY_EINVAL, "Cannot add metadata to an opaque node \"%s\".", ((struct lyd_node_opaq *)parent)->name);
@@ -1353,6 +1360,7 @@
     struct lyd_node *ret = NULL;
 
     LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_name, !prefix || !strcmp(prefix, module_name), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
 
     if (!ctx) {
         ctx = LYD_CTX(parent);
@@ -1380,6 +1388,7 @@
     struct lyd_node *ret = NULL;
 
     LY_CHECK_ARG_RET(ctx, parent || ctx, parent || node, name, module_ns, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, parent ? LYD_CTX(parent) : NULL, LY_EINVAL);
 
     if (!ctx) {
         ctx = LYD_CTX(parent);
@@ -2046,6 +2055,7 @@
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
             !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
 
     return lyd_new_path_(parent, ctx, NULL, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
 }
@@ -2057,6 +2067,8 @@
 {
     LY_CHECK_ARG_RET(ctx, parent || ctx, path, (path[0] == '/') || parent,
             !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
+
     return lyd_new_path_(parent, ctx, NULL, path, value, value_len, value_type, options, new_parent, new_node);
 }
 
@@ -2068,6 +2080,8 @@
 
     LY_CHECK_ARG_RET(ctx, ext, path, (path[0] == '/') || parent,
             !(options & LYD_NEW_PATH_BIN_VALUE) || !(options & LYD_NEW_PATH_CANON_VALUE), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? LYD_CTX(parent) : NULL, ctx, LY_EINVAL);
+
     return lyd_new_path_(parent, ctx, ext, path, value, 0, LYD_ANYDATA_STRING, options, node, NULL);
 }
 
@@ -2236,7 +2250,8 @@
     }
 
     /* resolve when and remove any invalid defaults */
-    LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, &node_exts, NULL, NULL, diff), cleanup);
+    LY_CHECK_GOTO(ret = lyd_validate_unres(&tree, NULL, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
+            cleanup);
 
 cleanup:
     ly_set_erase(&node_when, NULL);
@@ -2257,6 +2272,7 @@
     LY_ERR ret = LY_SUCCESS;
 
     LY_CHECK_ARG_RET(ctx, tree, *tree || ctx, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
     if (diff) {
         *diff = NULL;
     }
@@ -2288,13 +2304,15 @@
 }
 
 API LY_ERR
-lyd_new_implicit_module(struct lyd_node **tree, const struct lys_module *module, uint32_t implicit_options, struct lyd_node **diff)
+lyd_new_implicit_module(struct lyd_node **tree, const struct lys_module *module, uint32_t implicit_options,
+        struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_node *root, *d = NULL;
     struct ly_set node_when = {0}, node_exts = {0};
 
     LY_CHECK_ARG_RET(NULL, tree, module, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
     if (diff) {
         *diff = NULL;
     }
@@ -2303,7 +2321,8 @@
     LY_CHECK_GOTO(ret = lyd_new_implicit_r(NULL, tree, NULL, module, &node_when, &node_exts, NULL, implicit_options, diff), cleanup);
 
     /* resolve when and remove any invalid defaults */
-    LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, &node_exts, NULL, NULL, diff), cleanup);
+    LY_CHECK_GOTO(ret = lyd_validate_unres(tree, module, &node_when, LYXP_IGNORE_WHEN, &node_exts, NULL, NULL, diff),
+            cleanup);
 
     /* process nested nodes */
     LY_LIST_FOR(*tree, root) {
@@ -2656,6 +2675,7 @@
     struct lyd_node *iter;
 
     LY_CHECK_ARG_RET(NULL, parent, node, !parent->schema || (parent->schema->nodetype & LYD_NODE_INNER), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(LYD_CTX(parent), LYD_CTX(node), LY_EINVAL);
 
     LY_CHECK_RET(lyd_insert_check_schema(parent->schema, NULL, node->schema));
 
@@ -2683,6 +2703,7 @@
     struct lyd_node *iter;
 
     LY_CHECK_ARG_RET(NULL, node, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(sibling ? LYD_CTX(sibling) : NULL, LYD_CTX(node), LY_EINVAL);
 
     if (sibling) {
         LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
@@ -2724,6 +2745,7 @@
 lyd_insert_before(struct lyd_node *sibling, struct lyd_node *node)
 {
     LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
 
     LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
 
@@ -2743,6 +2765,7 @@
 lyd_insert_after(struct lyd_node *sibling, struct lyd_node *node)
 {
     LY_CHECK_ARG_RET(NULL, sibling, node, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(LYD_CTX(sibling), LYD_CTX(node), LY_EINVAL);
 
     LY_CHECK_RET(lyd_insert_check_schema(NULL, sibling->schema, node->schema));
 
@@ -3812,6 +3835,8 @@
     LY_ERR ret = LY_SUCCESS;
 
     LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(*target ? LYD_CTX(*target) : NULL, source ? LYD_CTX(source) : NULL, mod ? mod->ctx : NULL,
+            LY_EINVAL);
 
     if (!source) {
         /* nothing to merge */
@@ -4080,6 +4105,7 @@
     size_t pref_len, name_len;
 
     LY_CHECK_ARG_RET(NULL, module || strchr(name, ':'), name, NULL);
+    LY_CHECK_CTX_EQUAL_RET(first ? first->annotation->module->ctx : NULL, module ? module->ctx : NULL, NULL);
 
     if (!first) {
         return NULL;
@@ -4121,6 +4147,7 @@
     ly_bool found;
 
     LY_CHECK_ARG_RET(NULL, target, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
 
     if (!siblings || (siblings->schema && target->schema &&
             (lysc_data_parent(siblings->schema) != lysc_data_parent(target->schema)))) {
@@ -4288,6 +4315,7 @@
     struct lyd_node *target = NULL;
 
     LY_CHECK_ARG_RET(NULL, schema, !(schema->nodetype & (LYS_CHOICE | LYS_CASE)), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, schema->module->ctx, LY_EINVAL);
 
     if (!siblings || (siblings->schema && (lysc_data_parent(siblings->schema) != lysc_data_parent(schema)))) {
         /* no data or schema mismatch */
@@ -4330,6 +4358,7 @@
     struct lyd_node_inner *parent;
 
     LY_CHECK_ARG_RET(NULL, target, lysc_is_dup_inst_list(target->schema), set, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(siblings ? LYD_CTX(siblings) : NULL, LYD_CTX(target), LY_EINVAL);
 
     LY_CHECK_RET(ly_set_new(set));
 
diff --git a/src/tree_data.h b/src/tree_data.h
index 71db8dd..4d04581 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -671,6 +671,7 @@
 struct lyd_value_date_and_time {
     time_t time;        /**< UNIX timestamp */
     char *fractions_s;  /**< Optional fractions of a second */
+    ly_bool unknown_tz; /**< Whether the value is in the special -00:00 timezone. */
 };
 
 /**
@@ -1844,6 +1845,8 @@
 /**
  * @brief Compare 2 data nodes if they are equivalent.
  *
+ * Works correctly even if @p node1 and @p node2 have different contexts.
+ *
  * @param[in] node1 The first node to compare.
  * @param[in] node2 The second node to compare.
  * @param[in] options Various @ref datacompareoptions.
@@ -1855,6 +1858,8 @@
 /**
  * @brief Compare 2 lists of siblings if they are equivalent.
  *
+ * Works correctly even if @p node1 and @p node2 have different contexts.
+ *
  * @param[in] node1 The first sibling list to compare.
  * @param[in] node2 The second sibling list to compare.
  * @param[in] options Various @ref datacompareoptions.
@@ -1866,6 +1871,8 @@
 /**
  * @brief Compare 2 metadata.
  *
+ * If @p meta1 and @p meta2 have different contexts, they are never equivalent.
+ *
  * @param[in] meta1 First metadata.
  * @param[in] meta2 Second metadata.
  * @return LY_SUCCESS if the metadata are equivalent.
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 9b309f6..b4d8eaa 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -448,6 +448,7 @@
     const struct lysc_node *node = NULL;
 
     LY_CHECK_ARG_RET(NULL, module, name, NULL);
+    LY_CHECK_CTX_EQUAL_RET(parent ? parent->module->ctx : NULL, module->ctx, NULL);
     if (!nodetype) {
         nodetype = LYS_NODETYPE_MASK;
     }
@@ -483,6 +484,7 @@
     uint32_t i;
 
     LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
     if (!(options & LYXP_SCNODE_ALL)) {
         options |= LYXP_SCNODE;
     }
@@ -531,6 +533,7 @@
     uint32_t i;
 
     LY_CHECK_ARG_RET(NULL, cur_mod, expr, prefixes, set, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx_node ? ctx_node->module->ctx : NULL, cur_mod->ctx, LY_EINVAL);
     if (!(options & LYXP_SCNODE_ALL)) {
         options = LYXP_SCNODE;
     }
@@ -577,6 +580,7 @@
     uint32_t i;
 
     LY_CHECK_ARG_RET(NULL, ctx || ctx_node, xpath, set, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
     if (!(options & LYXP_SCNODE_ALL)) {
         options = LYXP_SCNODE;
     }
@@ -658,6 +662,7 @@
     struct ly_path *p = NULL;
 
     LY_CHECK_ARG_RET(ctx, ctx || ctx_node, path, set, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, LY_EINVAL);
 
     if (!ctx) {
         ctx = ctx_node->module->ctx;
@@ -691,6 +696,7 @@
     uint8_t oper;
 
     LY_CHECK_ARG_RET(ctx, ctx || ctx_node, NULL);
+    LY_CHECK_CTX_EQUAL_RET(ctx, ctx_node ? ctx_node->module->ctx : NULL, NULL);
 
     if (!ctx) {
         ctx = ctx_node->module->ctx;
@@ -889,9 +895,9 @@
     LY_ARRAY_COUNT_TYPE u, v;
     ly_bool found;
 
-    if (!lys_has_compiled(mod) || (mod->compiled && !lys_has_recompiled(mod))) {
+    if (LYS_IS_SINGLE_DEP_SET(mod)) {
         /* is already in a separate dep set */
-        if (!lys_has_groupings(mod)) {
+        if (!lys_has_groupings(mod) && !mod->parsed->features) {
             /* break the dep set here, no modules depend on this one */
             return LY_SUCCESS;
         }
@@ -926,8 +932,8 @@
         imports = mod->parsed->includes[v].submodule->imports;
         LY_ARRAY_FOR(imports, u) {
             mod2 = imports[u].module;
-            if (!lys_has_compiled(mod2) || (mod2->compiled && !lys_has_recompiled(mod2))) {
-                if (!lys_has_groupings(mod2)) {
+            if (LYS_IS_SINGLE_DEP_SET(mod2)) {
+                if (!lys_has_groupings(mod2) && !mod2->parsed->features) {
                     /* break the dep set here, no modules depend on this one */
                     continue;
                 }
@@ -991,7 +997,7 @@
 
     while (i < ctx_set->count) {
         m = ctx_set->objs[i];
-        if (!lys_has_compiled(m) || (m->compiled && !lys_has_recompiled(m))) {
+        if (LYS_IS_SINGLE_DEP_SET(m)) {
             /* remove it from the set, we are processing it now */
             ly_set_rm_index(ctx_set, i, NULL);
 
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 3f3d753..eb3c563 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -1143,6 +1143,10 @@
             ly_set_erase(&ctx->tpdfs_nodes, NULL);
             ly_set_erase(&ctx->grps_nodes, NULL);
         }
+        ly_set_rm_index(ctx->parsed_mods, ctx->parsed_mods->count - 1, NULL);
+        if (!ctx->parsed_mods->count) {
+            ly_set_free(ctx->parsed_mods, NULL);
+        }
         free(ctx);
     }
 }
@@ -1155,6 +1159,10 @@
             ly_set_erase(&ctx->tpdfs_nodes, NULL);
             ly_set_erase(&ctx->grps_nodes, NULL);
         }
+        ly_set_rm_index(ctx->parsed_mods, ctx->parsed_mods->count - 1, NULL);
+        if (!ctx->parsed_mods->count) {
+            ly_set_free(ctx->parsed_mods, NULL);
+        }
         lyxml_ctx_free(ctx->xmlctx);
         free(ctx);
     }
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index 67076b6..b6e3b7a 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -1035,10 +1035,10 @@
  * @return LY_EVALID - YANG rule violation
  */
 static LY_ERR
-lysp_get_submodule(struct lys_parser_ctx *pctx, struct lysp_include *inc)
+lysp_main_pmod_get_submodule(struct lys_parser_ctx *pctx, struct lysp_include *inc)
 {
     LY_ARRAY_COUNT_TYPE i;
-    struct lysp_module *main_pmod = pctx->parsed_mod->mod->parsed;
+    struct lysp_module *main_pmod = PARSER_CUR_PMOD(pctx)->mod->parsed;
 
     LY_ARRAY_FOR(main_pmod->includes, i) {
         if (strcmp(main_pmod->includes[i].name, inc->name)) {
@@ -1048,7 +1048,7 @@
         if (inc->rev[0] && strncmp(inc->rev, main_pmod->includes[i].rev, LY_REV_SIZE)) {
             LOGVAL(PARSER_CTX(pctx), LYVE_REFERENCE,
                     "Submodule %s includes different revision (%s) of the submodule %s:%s included by the main module %s.",
-                    ((struct lysp_submodule *)pctx->parsed_mod)->name, inc->rev,
+                    ((struct lysp_submodule *)PARSER_CUR_PMOD(pctx))->name, inc->rev,
                     main_pmod->includes[i].name, main_pmod->includes[i].rev, main_pmod->mod->name);
             return LY_EVALID;
         }
@@ -1061,7 +1061,7 @@
         LOGVAL(PARSER_CTX(pctx), LYVE_REFERENCE,
                 "YANG 1.1 requires all submodules to be included from main module. "
                 "But submodule \"%s\" includes submodule \"%s\" which is not included by main module \"%s\".",
-                ((struct lysp_submodule *)pctx->parsed_mod)->name, inc->name, main_pmod->mod->name);
+                ((struct lysp_submodule *)PARSER_CUR_PMOD(pctx))->name, inc->name, main_pmod->mod->name);
         return LY_EVALID;
     } else {
         return LY_ENOT;
@@ -1069,6 +1069,46 @@
 }
 
 /**
+ * @brief Try to find the parsed submodule in currenlty parsed modules for the given include record.
+ *
+ * @param[in] pctx main parser context
+ * @param[in] inc The include record with missing parsed submodule.
+ * @return LY_SUCCESS - the parsed submodule was found and inserted into the @p inc record
+ * @return LY_ENOT - the parsed module was not found.
+ * @return LY_EVALID - YANG rule violation
+ */
+static LY_ERR
+lysp_parsed_mods_get_submodule(struct lys_parser_ctx *pctx, struct lysp_include *inc)
+{
+    uint32_t i;
+    struct lysp_submodule *submod;
+
+    for (i = 0; i < pctx->parsed_mods->count - 1; ++i) {
+        submod = pctx->parsed_mods->objs[i];
+        if (!submod->is_submod) {
+            continue;
+        }
+
+        if (strcmp(submod->name, inc->name)) {
+            continue;
+        }
+
+        if (inc->rev[0] && submod->revs && strncmp(inc->rev, submod->revs[0].date, LY_REV_SIZE)) {
+            LOGVAL(PARSER_CTX(pctx), LYVE_REFERENCE,
+                    "Submodule %s includes different revision (%s) of the submodule %s:%s included by the main module %s.",
+                    ((struct lysp_submodule *)PARSER_CUR_PMOD(pctx))->name, inc->rev,
+                    submod->name, submod->revs[0].date, PARSER_CUR_PMOD(pctx)->mod->name);
+            return LY_EVALID;
+        }
+
+        inc->submodule = submod;
+        return LY_SUCCESS;
+    }
+
+    return LY_ENOT;
+}
+
+/**
  * @brief Make the copy of the given include record into the main module.
  *
  * YANG 1.0 does not require the main module to include all the submodules. Therefore, parsing submodules can cause
@@ -1083,7 +1123,7 @@
 {
     LY_ARRAY_COUNT_TYPE i;
     struct lysp_include *inc_new, *inc_tofill = NULL;
-    struct lysp_module *main_pmod = pctx->parsed_mod->mod->parsed;
+    struct lysp_module *main_pmod = PARSER_CUR_PMOD(pctx)->mod->parsed;
 
     /* first, try to find the corresponding record with missing parsed submodule */
     LY_ARRAY_FOR(main_pmod->includes, i) {
@@ -1117,7 +1157,7 @@
     struct ly_ctx *ctx = PARSER_CTX(pctx);
 
     LY_ARRAY_FOR(pmod->includes, u) {
-        LY_ERR ret = LY_SUCCESS;
+        LY_ERR ret = LY_SUCCESS, r;
         struct lysp_submodule *submod = NULL;
         struct lysp_include *inc = &pmod->includes[u];
 
@@ -1127,11 +1167,14 @@
 
         if (pmod->is_submod) {
             /* try to find the submodule in the main module or its submodules */
-            ret = lysp_get_submodule(pctx, inc);
-            LY_CHECK_RET(ret && ret != LY_ENOT, ret);
-            LY_CHECK_RET(ret == LY_SUCCESS, LY_SUCCESS); /* submodule found in linked with the inc */
+            ret = lysp_main_pmod_get_submodule(pctx, inc);
+            LY_CHECK_RET(ret != LY_ENOT, ret);
         }
 
+        /* try to use currently parsed submodule */
+        r = lysp_parsed_mods_get_submodule(pctx, inc);
+        LY_CHECK_RET(r != LY_ENOT, r);
+
         /* submodule not present in the main module, get the input data and parse it */
         if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
 search_clb:
@@ -1142,13 +1185,13 @@
                 struct lysp_load_module_check_data check_data = {0};
                 struct ly_in *in;
 
-                if (ctx->imp_clb(pctx->parsed_mod->mod->name, NULL, inc->name,
+                if (ctx->imp_clb(PARSER_CUR_PMOD(pctx)->mod->name, NULL, inc->name,
                         inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
                         &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
                     LY_CHECK_RET(ly_in_new_memory(submodule_data, &in));
                     check_data.name = inc->name;
                     check_data.revision = inc->rev[0] ? inc->rev : NULL;
-                    check_data.submoduleof = pctx->parsed_mod->mod->name;
+                    check_data.submoduleof = PARSER_CUR_PMOD(pctx)->mod->name;
                     lys_parse_submodule(ctx, in, format, pctx, lysp_load_module_check, &check_data, new_mods, &submod);
 
                     /* update inc pointer - parsing another (YANG 1.0) submodule can cause injecting
@@ -1169,7 +1212,7 @@
             if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* submodule was not received from the callback or there is no callback set */
                 lys_parse_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, pctx,
-                        pctx->parsed_mod->mod->name, 1, new_mods, (void **)&submod);
+                        PARSER_CUR_PMOD(pctx)->mod->name, 1, new_mods, (void **)&submod);
 
                 /* update inc pointer - parsing another (YANG 1.0) submodule can cause injecting
                  * submodule's include into main module, where it is missing */
@@ -1194,7 +1237,8 @@
         }
         if (!inc->submodule) {
             LOGVAL(ctx, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name,
-                    pctx->parsed_mod->is_submod ? ((struct lysp_submodule *)pctx->parsed_mod)->name : pctx->parsed_mod->mod->name);
+                    PARSER_CUR_PMOD(pctx)->is_submod ? ((struct lysp_submodule *)PARSER_CUR_PMOD(pctx))->name :
+                    PARSER_CUR_PMOD(pctx)->mod->name);
             return LY_EVALID;
         }
     }
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 9f78dd9..e28f69b 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -67,7 +67,7 @@
  * @param[in] PARENT parent statement where the KW is present - for logging.
  */
 #define PARSER_CHECK_STMTVER2_RET(CTX, KW, PARENT) \
-    if ((CTX)->parsed_mod->version < LYS_VERSION_1_1) {LOGVAL_PARSER((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
+    if (PARSER_CUR_PMOD(CTX)->version < LYS_VERSION_1_1) {LOGVAL_PARSER((CTX), LY_VCODE_INCHILDSTMT2, KW, PARENT); return LY_EVALID;}
 
 /* These 2 macros checks YANG's identifier grammar rule */
 #define is_yangidentstartchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')
@@ -138,7 +138,8 @@
     Y_MAYBE_STR_ARG       /**< optional YANG "string" rule */
 };
 
-#define PARSER_CTX(CTX) ((CTX)->parsed_mod->mod->ctx)
+#define PARSER_CUR_PMOD(CTX) ((struct lysp_module *)(CTX)->parsed_mods->objs[(CTX)->parsed_mods->count - 1])
+#define PARSER_CTX(CTX) (PARSER_CUR_PMOD(CTX)->mod->ctx)
 #define LOGVAL_PARSER(CTX, ...) LOGVAL((CTX) ? PARSER_CTX(CTX) : NULL, __VA_ARGS__)
 
 struct lys_parser_ctx {
@@ -147,7 +148,7 @@
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
-    struct lysp_module *parsed_mod;  /**< (sub)module being parsed */
+    struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lys_parser_ctx *main_ctx; /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
                                           otherwise it points to the beginning of this structure. */
@@ -162,7 +163,7 @@
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
-    struct lysp_module *parsed_mod;  /**< (sub)module being parsed */
+    struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lys_parser_ctx *main_ctx; /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
                                           otherwise it points to the beginning of this structure. */
@@ -185,7 +186,7 @@
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
     struct ly_set grps_nodes;        /**< Set of nodes that contain grouping(s). Invalid in case of
                                           submodule, use ::lys_parser_ctx.main_ctx instead. */
-    struct lysp_module *parsed_mod;  /**< (sub)module being parsed */
+    struct ly_set *parsed_mods;      /**< (sub)modules being parsed, the last one is the current */
     struct lys_parser_ctx *main_ctx; /**< This pointer must not be NULL. If this context deals with the submodule,
                                           then should be set to the context of the module to which it belongs,
                                           otherwise it points to the beginning of this structure. */
@@ -846,7 +847,7 @@
 /**
  * @brief Same as ::lysc_data_node() but never returns the node itself.
  */
-#define lysc_data_parent(SCHEMA) lysc_data_node((SCHEMA)->parent)
+#define lysc_data_parent(SCHEMA) lysc_data_node((SCHEMA) ? (SCHEMA)->parent : NULL)
 
 /**
  * @brief Get format-specific prefix for a module.
@@ -929,4 +930,13 @@
  */
 ly_bool lys_has_groupings(const struct lys_module *mod);
 
+/**
+ * @brief Learn whether the module qualifies for a single dep set with only this module or not.
+ *
+ * @param[in] mod Module to examine.
+ * @return Whether it qualifies as a single dep set or not.
+ */
+#define LYS_IS_SINGLE_DEP_SET(mod) \
+        (!(mod)->parsed->features && (!lys_has_compiled(mod) || ((mod)->compiled && !lys_has_recompiled(mod))))
+
 #endif /* LY_TREE_SCHEMA_INTERNAL_H_ */
diff --git a/src/validation.c b/src/validation.c
index fdfb95d..a6c9fdd 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -116,6 +116,7 @@
  * @param[in] tree Data tree.
  * @param[in] node Node whose relevant when conditions will be evaluated.
  * @param[in] schema Schema node of @p node. It may not be possible to use directly if @p node is opaque.
+ * @param[in] xpath_options Additional XPath options to use.
  * @param[out] disabled First when that evaluated false, if any.
  * @return LY_SUCCESS on success.
  * @return LY_EINCOMPLETE if a referenced node does not have its when evaluated.
@@ -123,7 +124,7 @@
  */
 static LY_ERR
 lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node, const struct lysc_node *schema,
-        const struct lysc_when **disabled)
+        uint32_t xpath_options, const struct lysc_when **disabled)
 {
     LY_ERR ret;
     const struct lyd_node *ctx_node;
@@ -151,7 +152,7 @@
             /* evaluate when */
             memset(&xp_set, 0, sizeof xp_set);
             ret = lyxp_eval(LYD_CTX(node), when->cond, schema->module, LY_VALUE_SCHEMA_RESOLVED, when->prefixes,
-                    ctx_node, tree, NULL, &xp_set, LYXP_SCHEMA);
+                    ctx_node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_options);
             lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
 
             /* return error or LY_EINCOMPLETE for dependant unresolved when */
@@ -178,6 +179,7 @@
  * If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
  * the first top-level sibling.
  * @param[in] node_when Set with nodes with "when" conditions.
+ * @param[in] xpath_options Additional XPath options to use.
  * @param[in,out] node_types Set with nodes with unresolved types, remove any with false "when" parents.
  * @param[in,out] diff Validation diff.
  * @return LY_SUCCESS on success.
@@ -185,7 +187,7 @@
  */
 static LY_ERR
 lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
-        struct ly_set *node_types, struct lyd_node **diff)
+        uint32_t xpath_options, struct ly_set *node_types, struct lyd_node **diff)
 {
     LY_ERR ret;
     uint32_t i, idx;
@@ -203,7 +205,7 @@
         LOG_LOCSET(node->schema, node, NULL, NULL);
 
         /* evaluate all when expressions that affect this node's existence */
-        ret = lyd_validate_node_when(*tree, node, node->schema, &disabled);
+        ret = lyd_validate_node_when(*tree, node, node->schema, xpath_options, &disabled);
         if (!ret) {
             if (disabled) {
                 /* when false */
@@ -308,8 +310,8 @@
 }
 
 LY_ERR
-lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, struct ly_set *node_exts,
-        struct ly_set *node_types, struct ly_set *meta_types, struct lyd_node **diff)
+lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t when_xp_opts,
+        struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types, struct lyd_node **diff)
 {
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
@@ -319,7 +321,7 @@
         uint32_t prev_count;
         do {
             prev_count = node_when->count;
-            LY_CHECK_RET(lyd_validate_unres_when(tree, mod, node_when, node_types, diff));
+            LY_CHECK_RET(lyd_validate_unres_when(tree, mod, node_when, when_xp_opts, node_types, diff));
             /* there must have been some when conditions resolved */
         } while (prev_count > node_when->count);
 
@@ -786,7 +788,7 @@
     }
 
     /* evaluate all when */
-    ret = lyd_validate_node_when(tree, dummy, snode, disabled);
+    ret = lyd_validate_node_when(tree, dummy, snode, 0, disabled);
     if (ret == LY_EINCOMPLETE) {
         /* all other when must be resolved by now */
         LOGINT(snode->module->ctx);
@@ -1372,7 +1374,8 @@
 lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *sparent,
         const struct lys_module *mod, uint32_t val_opts, uint32_t int_opts)
 {
-    const char *innode = NULL;
+    LY_ERR r;
+    const char *innode;
     struct lyd_node *next = NULL, *node;
 
     /* validate all restrictions of nodes themselves */
@@ -1387,30 +1390,43 @@
         /* opaque data */
         if (!node->schema) {
             LOGVAL(LYD_CTX(node), LYVE_DATA, "Invalid opaque node \"%s\" found.", ((struct lyd_node_opaq *)node)->name.name);
-            LOG_LOCBACK(0, 1, 0, 0);
+            LOG_LOCBACK(1, 1, 0, 0);
             return LY_EVALID;
         }
 
-        /* no state/input/output data */
+        /* no state/input/output/op data */
+        innode = NULL;
         if ((val_opts & LYD_VALIDATE_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
             innode = "state";
-            goto unexpected_node;
         } else if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION)) && (node->schema->flags & LYS_IS_OUTPUT)) {
             innode = "output";
-            goto unexpected_node;
         } else if ((int_opts & LYD_INTOPT_REPLY) && (node->schema->flags & LYS_IS_INPUT)) {
             innode = "input";
-            goto unexpected_node;
+        } else if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_RPC)) {
+            innode = "rpc";
+        } else if (!(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_ACTION)) {
+            innode = "action";
+        } else if (!(int_opts & LYD_INTOPT_NOTIF) && (node->schema->nodetype == LYS_NOTIF)) {
+            innode = "notification";
+        }
+        if (innode) {
+            LOGVAL(LYD_CTX(node), LY_VCODE_UNEXPNODE, innode, node->schema->name);
+            LOG_LOCBACK(1, 1, 0, 0);
+            return LY_EVALID;
         }
 
         /* obsolete data */
         lyd_validate_obsolete(node);
 
         /* node's musts */
-        LY_CHECK_RET(lyd_validate_must(node, int_opts));
+        if ((r = lyd_validate_must(node, int_opts))) {
+            LOG_LOCBACK(1, 1, 0, 0);
+            return r;
+        }
 
         /* node value was checked by plugins */
 
+        /* next iter */
         LOG_LOCBACK(1, 1, 0, 0);
     }
 
@@ -1440,11 +1456,6 @@
     }
 
     return LY_SUCCESS;
-
-unexpected_node:
-    LOGVAL(LYD_CTX(node), LY_VCODE_UNEXPNODE, innode, node->schema->name);
-    LOG_LOCBACK(1, 1, 0, 0);
-    return LY_EVALID;
 }
 
 /**
@@ -1574,7 +1585,7 @@
         }
 
         /* finish incompletely validated terminal values/attributes and when conditions */
-        ret = lyd_validate_unres(first2, mod, node_when_p, node_exts_p, node_types_p, meta_types_p, diff);
+        ret = lyd_validate_unres(first2, mod, node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* perform final validation that assumes the data tree is final */
@@ -1594,6 +1605,7 @@
 lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff)
 {
     LY_CHECK_ARG_RET(NULL, tree, *tree || ctx, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
     if (!ctx) {
         ctx = LYD_CTX(*tree);
     }
@@ -1608,6 +1620,7 @@
 lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff)
 {
     LY_CHECK_ARG_RET(NULL, tree, *tree || module, LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module ? module->ctx : NULL, LY_EINVAL);
     if (diff) {
         *diff = NULL;
     }
@@ -1748,7 +1761,7 @@
 
     /* finish incompletely validated terminal values/attributes and when conditions on the full tree */
     LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL,
-            node_when_p, node_exts_p, node_types_p, meta_types_p, diff), cleanup);
+            node_when_p, 0, node_exts_p, node_types_p, meta_types_p, diff), cleanup);
 
     /* perform final validation of the operation/notification */
     lyd_validate_obsolete(op_node);
@@ -1780,6 +1793,7 @@
 
     LY_CHECK_ARG_RET(NULL, op_tree, !op_tree->parent, !dep_tree || !dep_tree->parent, (data_type == LYD_TYPE_RPC_YANG) ||
             (data_type == LYD_TYPE_NOTIF_YANG) || (data_type == LYD_TYPE_REPLY_YANG), LY_EINVAL);
+    LY_CHECK_CTX_EQUAL_RET(LYD_CTX(op_tree), dep_tree ? LYD_CTX(dep_tree) : NULL, LY_EINVAL);
     if (diff) {
         *diff = NULL;
     }
diff --git a/src/validation.h b/src/validation.h
index 704d4b3..b8b1a98 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -55,6 +55,7 @@
  * If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
  * the first top-level sibling.
  * @param[in] node_when Set with nodes with "when" conditions, can be NULL.
+ * @param[in] when_xp_opts Additional XPath options to use for evaluating "when".
  * @param[in] node_exts Set with nodes with extension instances with validation plugin callback, can be NULL.
  * @param[in] node_types Set with nodes with unresolved types, can be NULL
  * @param[in] meta_types Set with metadata with unresolved types, can be NULL.
@@ -62,7 +63,8 @@
  * @return LY_ERR value.
  */
 LY_ERR lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
-        struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types, struct lyd_node **diff);
+        uint32_t when_xp_opts, struct ly_set *node_exts, struct ly_set *node_types, struct ly_set *meta_types,
+        struct lyd_node **diff);
 
 /**
  * @brief Validate new siblings. Specifically, check duplicated instances, autodelete default values and cases.
diff --git a/src/xpath.c b/src/xpath.c
index 88c9163..15404c7 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -1272,31 +1272,6 @@
 }
 
 /**
- * @brief Replace a node in a set with another. Context position aware.
- *
- * @param[in] set Set to use.
- * @param[in] node Node to insert to @p set.
- * @param[in] pos Sort position of @p node. If left 0, it is filled just before sorting.
- * @param[in] node_type Node type of @p node.
- * @param[in] idx Index in @p set of the node to replace.
- */
-static void
-set_replace_node(struct lyxp_set *set, const struct lyd_node *node, uint32_t pos, enum lyxp_node_type node_type, uint32_t idx)
-{
-    assert(set && (idx < set->used));
-
-    if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
-        set_remove_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
-    }
-    set->val.nodes[idx].node = (struct lyd_node *)node;
-    set->val.nodes[idx].type = node_type;
-    set->val.nodes[idx].pos = pos;
-    if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
-        set_insert_node_hash(set, set->val.nodes[idx].node, set->val.nodes[idx].type);
-    }
-}
-
-/**
  * @brief Set all nodes with ctx 1 to a new unique context value.
  *
  * @param[in] set Set to modify.
@@ -1726,33 +1701,6 @@
     return ret - 1;
 }
 
-/**
- * @brief Remove duplicate entries in a sorted node set.
- *
- * @param[in] set Sorted set to check.
- * @return LY_ERR (LY_EEXIST if some duplicates are found)
- */
-static LY_ERR
-set_sorted_dup_node_clean(struct lyxp_set *set)
-{
-    uint32_t i = 0;
-    LY_ERR ret = LY_SUCCESS;
-
-    if (set->used > 1) {
-        while (i < set->used - 1) {
-            if ((set->val.nodes[i].node == set->val.nodes[i + 1].node) &&
-                    (set->val.nodes[i].type == set->val.nodes[i + 1].type)) {
-                set_remove_node_none(set, i + 1);
-                ret = LY_EEXIST;
-            }
-            ++i;
-        }
-    }
-
-    set_remove_nodes_none(set);
-    return ret;
-}
-
 #endif
 
 /**
@@ -5567,9 +5515,9 @@
 static LY_ERR
 moveto_node(struct lyxp_set *set, const struct lys_module *moveto_mod, const char *ncname, uint32_t options)
 {
-    uint32_t i;
+    LY_ERR r, rc = LY_SUCCESS;
     const struct lyd_node *siblings, *sub;
-    LY_ERR rc;
+    struct lyxp_set result;
 
     if (options & LYXP_SKIP_EXPR) {
         return LY_SUCCESS;
@@ -5580,9 +5528,10 @@
         return LY_EVALID;
     }
 
-    for (i = 0; i < set->used; ) {
-        ly_bool replaced = 0;
+    /* init result set */
+    set_init(&result, set);
 
+    for (uint32_t i = 0; i < set->used; ++i) {
         if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
             assert(!set->val.nodes[i].node);
 
@@ -5594,27 +5543,26 @@
         }
 
         for (sub = siblings; sub; sub = sub->next) {
-            rc = moveto_node_check(sub, set, ncname, moveto_mod, options);
-            if (rc == LY_SUCCESS) {
-                if (!replaced) {
-                    set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
-                    replaced = 1;
-                } else {
-                    set_insert_node(set, sub, 0, LYXP_NODE_ELEM, i);
-                }
-                ++i;
-            } else if (rc == LY_EINCOMPLETE) {
-                return rc;
+            r = moveto_node_check(sub, set, ncname, moveto_mod, options);
+            if (r == LY_SUCCESS) {
+                /* matching node */
+                set_insert_node(&result, sub, 0, LYXP_NODE_ELEM, result.used);
+            } else if (r == LY_EINCOMPLETE) {
+                rc = r;
+                goto cleanup;
             }
         }
-
-        if (!replaced) {
-            /* no match */
-            set_remove_node(set, i);
-        }
     }
 
-    return LY_SUCCESS;
+    /* move result to the set */
+    lyxp_set_free_content(set);
+    *set = result;
+    result.type = LYXP_SET_NUMBER;
+    assert(!set_sort(set));
+
+cleanup:
+    lyxp_set_free_content(&result);
+    return rc;
 }
 
 /**
@@ -5634,10 +5582,14 @@
     LY_ERR ret = LY_SUCCESS;
     uint32_t i;
     const struct lyd_node *siblings;
+    struct lyxp_set result;
     struct lyd_node *sub, *inst = NULL;
 
     assert(scnode && (!(scnode->nodetype & (LYS_LIST | LYS_LEAFLIST)) || predicates));
 
+    /* init result set */
+    set_init(&result, set);
+
     if (options & LYXP_SKIP_EXPR) {
         goto cleanup;
     }
@@ -5665,7 +5617,7 @@
         LY_CHECK_GOTO(ret = lyd_create_term2(scnode, &predicates[0].value, &inst), cleanup);
     }
 
-    for (i = 0; i < set->used; ) {
+    for (i = 0; i < set->used; ++i) {
         siblings = NULL;
 
         if ((set->val.nodes[i].type == LYXP_NODE_ROOT_CONFIG) || (set->val.nodes[i].type == LYXP_NODE_ROOT)) {
@@ -5693,15 +5645,18 @@
 
         if (sub) {
             /* pos filled later */
-            set_replace_node(set, sub, 0, LYXP_NODE_ELEM, i);
-            ++i;
-        } else {
-            /* no match */
-            set_remove_node(set, i);
+            set_insert_node(&result, sub, 0, LYXP_NODE_ELEM, result.used);
         }
     }
 
+    /* move result to the set */
+    lyxp_set_free_content(set);
+    *set = result;
+    result.type = LYXP_SET_NUMBER;
+    assert(!set_sort(set));
+
 cleanup:
+    lyxp_set_free_content(&result);
     lyd_free_tree(inst);
     return ret;
 }
@@ -6401,9 +6356,10 @@
 static LY_ERR
 moveto_parent(struct lyxp_set *set, ly_bool all_desc, uint32_t options)
 {
-    LY_ERR rc;
+    LY_ERR rc = LY_SUCCESS;
     struct lyd_node *node, *new_node;
     enum lyxp_node_type new_type;
+    struct lyxp_set result;
 
     if (options & LYXP_SKIP_EXPR) {
         return LY_SUCCESS;
@@ -6420,6 +6376,9 @@
         LY_CHECK_RET(rc);
     }
 
+    /* init result set */
+    set_init(&result, set);
+
     for (uint32_t i = 0; i < set->used; ++i) {
         node = set->val.nodes[i].node;
 
@@ -6430,39 +6389,45 @@
         } else if (set->val.nodes[i].type == LYXP_NODE_META) {
             new_node = set->val.meta[i].meta->parent;
             if (!new_node) {
-                LOGINT_RET(set->ctx);
+                LOGINT(set->ctx);
+                rc = LY_EINT;
+                goto cleanup;
             }
         } else {
             /* root does not have a parent */
-            set_remove_node_none(set, i);
             continue;
         }
 
         /* when check */
-        if (!(options & LYXP_IGNORE_WHEN) && new_node && lysc_has_when(new_node->schema) && !(new_node->flags & LYD_WHEN_TRUE)) {
-            return LY_EINCOMPLETE;
+        if (!(options & LYXP_IGNORE_WHEN) && new_node && lysc_has_when(new_node->schema) &&
+                !(new_node->flags & LYD_WHEN_TRUE)) {
+            rc = LY_EINCOMPLETE;
+            goto cleanup;
         }
 
         if (!new_node) {
             /* node already there can also be the root */
             new_type = set->root_type;
-
         } else {
             /* node has a standard parent (it can equal the root, it's not the root yet since they are fake) */
             new_type = LYXP_NODE_ELEM;
         }
 
-        if (set_dup_node_check(set, new_node, new_type, -1)) {
-            set_remove_node_none(set, i);
-        } else {
-            set_replace_node(set, new_node, 0, new_type, i);
+        /* check for duplicates, several nodes may have the same parent */
+        if (!set_dup_node_check(&result, new_node, new_type, -1)) {
+            set_insert_node(&result, new_node, 0, new_type, result.used);
         }
     }
 
-    set_remove_nodes_none(set);
-    assert(!set_sort(set) && !set_sorted_dup_node_clean(set));
+    /* move result to the set */
+    lyxp_set_free_content(set);
+    *set = result;
+    result.type = LYXP_SET_NUMBER;
+    assert(!set_sort(set));
 
-    return LY_SUCCESS;
+cleanup:
+    lyxp_set_free_content(&result);
+    return rc;
 }
 
 /**
diff --git a/tests/utests/schema/test_parser_yang.c b/tests/utests/schema/test_parser_yang.c
index 84492c8..9625ea9 100644
--- a/tests/utests/schema/test_parser_yang.c
+++ b/tests/utests/schema/test_parser_yang.c
@@ -75,19 +75,23 @@
 static int
 setup(void **state)
 {
+    struct lysp_module *pmod;
+
     UTEST_SETUP;
 
     /* allocate parser context */
     YCTX = calloc(1, sizeof(*YCTX));
     YCTX->format = LYS_IN_YANG;
+    ly_set_new(&YCTX->parsed_mods);
 
     /* allocate new parsed module */
-    YCTX->parsed_mod = calloc(1, sizeof *YCTX->parsed_mod);
+    pmod = calloc(1, sizeof *pmod);
+    ly_set_add(YCTX->parsed_mods, pmod, 1, NULL);
 
     /* allocate new module */
-    YCTX->parsed_mod->mod = calloc(1, sizeof *YCTX->parsed_mod->mod);
-    YCTX->parsed_mod->mod->ctx = UTEST_LYCTX;
-    YCTX->parsed_mod->mod->parsed = YCTX->parsed_mod;
+    pmod->mod = calloc(1, sizeof *pmod->mod);
+    pmod->mod->ctx = UTEST_LYCTX;
+    pmod->mod->parsed = pmod;
 
     /* initilize and use the global easily available and customizable input handler */
     in.line = 1;
@@ -100,9 +104,10 @@
 static int
 teardown(void **state)
 {
-    lys_module_free(YCTX->parsed_mod->mod);
+    lys_module_free(PARSER_CUR_PMOD(YCTX)->mod);
     LOG_LOCBACK(0, 0, 0, 1);
 
+    ly_set_free(YCTX->parsed_mods, NULL);
     free(YCTX);
     YCTX = NULL;
 
@@ -477,7 +482,7 @@
     uint32_t value = 0;
     struct lysp_ext_instance *ext = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     in.current = " 1invalid; ...";
     assert_int_equal(LY_EVALID, parse_minelements(YCTX, &value, &flags, &ext));
@@ -500,7 +505,7 @@
     flags = value = 0;
     TEST_MINMAX_SUCCESS(" 1 {m:ext;} ...", YCTX, LYS_SET_MIN, 1);
     assert_non_null(ext);
-    FREE_ARRAY(YCTX->parsed_mod->mod->ctx, ext, lysp_ext_instance_free);
+    FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, ext, lysp_ext_instance_free);
     ext = NULL;
 
     flags = value = 0;
@@ -532,7 +537,7 @@
     flags = value = 0;
     TEST_MINMAX_SUCCESS(" 1 {m:ext;} ...", YCTX, LYS_SET_MAX, 1);
     assert_non_null(ext);
-    FREE_ARRAY(YCTX->parsed_mod->mod->ctx, ext, lysp_ext_instance_free);
+    FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, ext, lysp_ext_instance_free);
     ext = NULL;
 
     flags = value = 0;
@@ -544,32 +549,36 @@
 static struct lysp_module *
 mod_renew(struct lys_yang_parser_ctx *ctx)
 {
-    struct ly_ctx *ly_ctx = ctx->parsed_mod->mod->ctx;
+    struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
+    struct lysp_module *pmod;
 
-    lys_module_free(ctx->parsed_mod->mod);
-    ctx->parsed_mod = calloc(1, sizeof *ctx->parsed_mod);
-    ctx->parsed_mod->mod = calloc(1, sizeof *ctx->parsed_mod->mod);
-    ctx->parsed_mod->mod->parsed = ctx->parsed_mod;
-    ctx->parsed_mod->mod->ctx = ly_ctx;
+    lys_module_free(PARSER_CUR_PMOD(ctx)->mod);
+    pmod = calloc(1, sizeof *pmod);
+    ctx->parsed_mods->objs[0] = pmod;
+    pmod->mod = calloc(1, sizeof *pmod->mod);
+    pmod->mod->parsed = pmod;
+    pmod->mod->ctx = ly_ctx;
 
     ctx->in->line = 1;
 
-    return ctx->parsed_mod;
+    return pmod;
 }
 
 static struct lysp_submodule *
 submod_renew(struct lys_yang_parser_ctx *ctx)
 {
-    struct ly_ctx *ly_ctx = ctx->parsed_mod->mod->ctx;
+    struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
+    struct lysp_submodule *submod;
 
-    lys_module_free(ctx->parsed_mod->mod);
-    ctx->parsed_mod = calloc(1, sizeof(struct lysp_submodule));
-    ctx->parsed_mod->mod = calloc(1, sizeof *ctx->parsed_mod->mod);
-    lydict_insert(ly_ctx, "name", 0, &ctx->parsed_mod->mod->name);
-    ctx->parsed_mod->mod->parsed = ctx->parsed_mod;
-    ctx->parsed_mod->mod->ctx = ly_ctx;
+    lys_module_free(PARSER_CUR_PMOD(ctx)->mod);
+    submod = calloc(1, sizeof *submod);
+    ctx->parsed_mods->objs[0] = submod;
+    submod->mod = calloc(1, sizeof *submod->mod);
+    lydict_insert(ly_ctx, "name", 0, &submod->mod->name);
+    submod->mod->parsed = (struct lysp_module *)submod;
+    submod->mod->ctx = ly_ctx;
 
-    return (struct lysp_submodule *)ctx->parsed_mod;
+    return submod;
 }
 
 static LY_ERR
@@ -677,7 +686,7 @@
     TEST_GENERIC("identity test;}", mod->identities,
             assert_string_equal("test", mod->identities[0].name));
     /* import */
-    ly_ctx_set_module_imp_clb(YCTX->parsed_mod->mod->ctx, test_imp_clb, "module zzz { namespace urn:zzz; prefix z;}");
+    ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module zzz { namespace urn:zzz; prefix z;}");
     TEST_GENERIC("import zzz {prefix z;}}", mod->imports,
             assert_string_equal("zzz", mod->imports[0].name));
 
@@ -695,21 +704,21 @@
     LOG_LOCBACK(0, 0, 0, 1);
 
     in.current = "module name10 {yang-version 1.1;namespace urn:x;prefix \"x\";import zzz {prefix y;}import zzz {prefix z;}}";
-    assert_int_equal(lys_parse_mem(YCTX->parsed_mod->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_SUCCESS);
+    assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_SUCCESS);
     CHECK_LOG_CTX("Single revision of the module \"zzz\" imported twice.", NULL);
 
     /* include */
-    ly_ctx_set_module_imp_clb(YCTX->parsed_mod->mod->ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}");
+    ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "module xxx { namespace urn:xxx; prefix x;}");
     in.current = "module" SCHEMA_BEGINNING "include xxx;}";
-    assert_int_equal(lys_parse_mem(YCTX->parsed_mod->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
+    assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
     CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, "Including \"xxx\" submodule into \"name\" failed.", NULL);
 
-    ly_ctx_set_module_imp_clb(YCTX->parsed_mod->mod->ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name {prefix w;}}");
+    ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to wrong-name {prefix w;}}");
     in.current = "module" SCHEMA_BEGINNING "include xxx;}";
-    assert_int_equal(lys_parse_mem(YCTX->parsed_mod->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
+    assert_int_equal(lys_parse_mem(PARSER_CUR_PMOD(YCTX)->mod->ctx, in.current, LYS_IN_YANG, NULL), LY_EVALID);
     CHECK_LOG_CTX("Parsing module \"name\" failed.", NULL, "Including \"xxx\" submodule into \"name\" failed.", NULL);
 
-    ly_ctx_set_module_imp_clb(YCTX->parsed_mod->mod->ctx, test_imp_clb, "submodule xxx {belongs-to name {prefix x;}}");
+    ly_ctx_set_module_imp_clb(PARSER_CUR_PMOD(YCTX)->mod->ctx, test_imp_clb, "submodule xxx {belongs-to name {prefix x;}}");
     TEST_GENERIC("include xxx;}", mod->includes,
             assert_string_equal("xxx", mod->includes[0].name));
 
@@ -759,7 +768,7 @@
 
     in.current = "module " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
     m = calloc(1, sizeof *m);
-    m->ctx = YCTX->parsed_mod->mod->ctx;
+    m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
     assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
     CHECK_LOG_CTX("Trailing garbage \"module q {names...\" after module, expected end-of-input.", "Line number 1.");
     yang_parser_ctx_free(ctx_p);
@@ -767,7 +776,7 @@
 
     in.current = "prefix " SCHEMA_BEGINNING "}";
     m = calloc(1, sizeof *m);
-    m->ctx = YCTX->parsed_mod->mod->ctx;
+    m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
     assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
     CHECK_LOG_CTX("Invalid keyword \"prefix\", expected \"module\" or \"submodule\".", "Line number 1.");
     yang_parser_ctx_free(ctx_p);
@@ -775,7 +784,7 @@
 
     in.current = "module " SCHEMA_BEGINNING "leaf enum {type enumeration {enum seven { position 7;}}}}";
     m = calloc(1, sizeof *m);
-    m->ctx = YCTX->parsed_mod->mod->ctx;
+    m->ctx = PARSER_CUR_PMOD(YCTX)->mod->ctx;
     assert_int_equal(LY_EVALID, yang_parse_module(&ctx_p, &in, m));
     CHECK_LOG_CTX("Invalid keyword \"position\" as a child of \"enum\".", "Line number 1.");
     yang_parser_ctx_free(ctx_p);
@@ -828,12 +837,12 @@
     submod = submod_renew(YCTX);
 
     in.current = "submodule " SCHEMA_BEGINNING "} module q {namespace urn:q;prefixq;}";
-    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, YCTX->parsed_mod->mod->ctx, (struct lys_parser_ctx *)YCTX, YCTX->in, &submod));
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lys_parser_ctx *)YCTX, YCTX->in, &submod));
     CHECK_LOG_CTX("Trailing garbage \"module q {names...\" after submodule, expected end-of-input.", "Line number 1.");
     yang_parser_ctx_free(ctx_p);
 
     in.current = "prefix " SCHEMA_BEGINNING "}";
-    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, YCTX->parsed_mod->mod->ctx, (struct lys_parser_ctx *)YCTX, YCTX->in, &submod));
+    assert_int_equal(LY_EVALID, yang_parse_submodule(&ctx_p, PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lys_parser_ctx *)YCTX, YCTX->in, &submod));
     CHECK_LOG_CTX("Invalid keyword \"prefix\", expected \"module\" or \"submodule\".", "Line number 1.");
     yang_parser_ctx_free(ctx_p);
     submod = submod_renew(YCTX);
@@ -852,7 +861,7 @@
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     TEST_DUP_GENERIC(" test {deviate not-supported;", MEMBER, VALUE1, VALUE2, parse_deviation, \
-                     &d, "1", FREE_ARRAY(YCTX->parsed_mod->mod->ctx, d, lysp_deviation_free); d = NULL)
+                     &d, "1", FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, d, lysp_deviation_free); d = NULL)
 
     TEST_DUP("description", "a", "b");
     TEST_DUP("reference", "a", "b");
@@ -862,21 +871,21 @@
     assert_int_equal(LY_SUCCESS, parse_deviation(YCTX, &d));
     assert_non_null(d);
     assert_string_equal(" ...", in.current);
-    FREE_ARRAY(YCTX->parsed_mod->mod->ctx, d, lysp_deviation_free);
+    FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, d, lysp_deviation_free);
     d = NULL;
 
     /* missing mandatory substatement */
     in.current = " test {description text;}";
     assert_int_equal(LY_EVALID, parse_deviation(YCTX, &d));
     CHECK_LOG_CTX("Missing mandatory keyword \"deviate\" as a child of \"deviation\".", "Line number 1.");
-    FREE_ARRAY(YCTX->parsed_mod->mod->ctx, d, lysp_deviation_free);
+    FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, d, lysp_deviation_free);
     d = NULL;
 
     /* invalid substatement */
     in.current = " test {deviate not-supported; status obsolete;}";
     assert_int_equal(LY_EVALID, parse_deviation(YCTX, &d));
     CHECK_LOG_CTX("Invalid keyword \"status\" as a child of \"deviation\".", "Line number 1.");
-    FREE_ARRAY(YCTX->parsed_mod->mod->ctx, d, lysp_deviation_free);
+    FREE_ARRAY(PARSER_CUR_PMOD(YCTX)->mod->ctx, d, lysp_deviation_free);
     d = NULL;
 #undef TEST_DUP
 }
@@ -886,7 +895,7 @@
                     assert_int_equal(LY_SUCCESS, parse_deviate(YCTX, &d));\
                     assert_non_null(d);\
                     assert_string_equal(REMAIN_TEXT, in.current);\
-                    lysp_deviate_free(YCTX->parsed_mod->mod->ctx, d); free(d); d = NULL
+                    lysp_deviate_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, d); free(d); d = NULL
 
 static void
 test_deviate(void **state)
@@ -896,7 +905,7 @@
     /* invalid cardinality */
 #define TEST_DUP(TYPE, MEMBER, VALUE1, VALUE2) \
     TEST_DUP_GENERIC(TYPE" {", MEMBER, VALUE1, VALUE2, parse_deviate, \
-                     &d, "1", lysp_deviate_free(YCTX->parsed_mod->mod->ctx, d); free(d); d = NULL)
+                     &d, "1", lysp_deviate_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, d); free(d); d = NULL)
 
     TEST_DUP("add", "config", "true", "false");
 #if 0
@@ -923,7 +932,7 @@
     in.current = " "DEV" {"STMT" "VALUE";}..."; \
     assert_int_equal(LY_EVALID, parse_deviate(YCTX, &d)); \
     CHECK_LOG_CTX("Deviate \""DEV"\" does not support keyword \""STMT"\".", "Line number 1.");\
-    lysp_deviate_free(YCTX->parsed_mod->mod->ctx, d); free(d); d = NULL
+    lysp_deviate_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, d); free(d); d = NULL
 
     TEST_NOT_SUP("not-supported", "units", "meters");
     TEST_NOT_SUP("not-supported", "must", "1");
@@ -956,7 +965,7 @@
 {
     struct lysp_node_container *c = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     YCTX->main_ctx = (struct lys_parser_ctx *)YCTX;
 
     /* invalid cardinality */
@@ -964,7 +973,7 @@
     in.current = "cont {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node**)&c)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)c); c = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)c); c = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("description", "text1", "text2");
@@ -988,24 +997,24 @@
     assert_non_null(c->typedefs);
     ly_set_erase(&YCTX->tpdfs_nodes, NULL);
     ly_set_erase(&YCTX->grps_nodes, NULL);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c); c = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c); c = NULL;
 
     /* invalid */
     in.current = " cont {augment /root;} ...";
     assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
     CHECK_LOG_CTX("Invalid keyword \"augment\" as a child of \"container\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c); c = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c); c = NULL;
     in.current = " cont {nonsence true;} ...";
     assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
     CHECK_LOG_CTX("Invalid character sequence \"nonsence\", expected a keyword.", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c); c = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c); c = NULL;
 
-    YCTX->parsed_mod->version = 1; /* simulate YANG 1.0 */
+    PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
     in.current = " cont {action x;} ...";
     assert_int_equal(LY_EVALID, parse_container(YCTX, NULL, (struct lysp_node **)&c));
     CHECK_LOG_CTX("Invalid keyword \"action\" as a child of \"container\" - "
             "the statement is allowed only in YANG 1.1 modules.", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c); c = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c); c = NULL;
 }
 
 static void
@@ -1018,7 +1027,7 @@
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node**)&l)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)l); l = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("default", "x", "y");
@@ -1040,25 +1049,25 @@
     assert_string_equal("yyy", l->units);
     assert_string_equal("string", l->type.name);
     assert_non_null(l->musts);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 
     /* full content - now with mandatory */
     in.current = "l {mandatory true; type string;} ...";
     assert_int_equal(LY_SUCCESS, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
     CHECK_LYSP_NODE(l, NULL, 0, LYS_MAND_TRUE, 0, "l", 0, LYS_LEAF, 0, NULL, 0);
     assert_string_equal("string", l->type.name);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 
     /* invalid */
     in.current = " l {description \"missing type\";} ...";
     assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
     CHECK_LOG_CTX("Missing mandatory keyword \"type\" as a child of \"leaf\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 
     in.current = "l { type iid { path qpud wrong {";
     assert_int_equal(LY_EVALID, parse_leaf(YCTX, NULL, (struct lysp_node **)&l));
     CHECK_LOG_CTX("Invalid character sequence \"wrong\", expected a keyword.", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 }
 
 static void
@@ -1066,14 +1075,14 @@
 {
     struct lysp_node_leaflist *ll = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "ll {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node**)&ll)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)ll); ll = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)ll); ll = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("description", "text1", "text2");
@@ -1103,7 +1112,7 @@
     assert_string_equal("string", ll->type.name);
     assert_non_null(ll->musts);
     assert_int_equal(LYS_CONFIG_R | LYS_STATUS_CURR | LYS_ORDBY_USER | LYS_SET_MAX, ll->flags);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ll); ll = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ll); ll = NULL;
 
     /* full content - now with min-elements */
     in.current = "ll {min-elements 10; type string;} ...";
@@ -1113,19 +1122,19 @@
     assert_int_equal(0, ll->max);
     assert_int_equal(10, ll->min);
     assert_int_equal(LYS_SET_MIN, ll->flags);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ll); ll = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ll); ll = NULL;
 
     /* invalid */
     in.current = " ll {description \"missing type\";} ...";
     assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
     CHECK_LOG_CTX("Missing mandatory keyword \"type\" as a child of \"leaf-list\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ll); ll = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ll); ll = NULL;
 
-    YCTX->parsed_mod->version = 1; /* simulate YANG 1.0 - default statement is not allowed */
+    PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 - default statement is not allowed */
     in.current = " ll {default xx; type string;} ...";
     assert_int_equal(LY_EVALID, parse_leaflist(YCTX, NULL, (struct lysp_node **)&ll));
     CHECK_LOG_CTX("Invalid keyword \"default\" as a child of \"leaf-list\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ll); ll = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ll); ll = NULL;
 }
 
 static void
@@ -1133,7 +1142,7 @@
 {
     struct lysp_node_list *l = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     YCTX->main_ctx = (struct lys_parser_ctx *)YCTX;
 
     /* invalid cardinality */
@@ -1141,7 +1150,7 @@
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_list(YCTX, NULL, (struct lysp_node**)&l)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)l); l = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("description", "text1", "text2");
@@ -1171,14 +1180,14 @@
     assert_non_null(l->musts);
     ly_set_erase(&YCTX->tpdfs_nodes, NULL);
     ly_set_erase(&YCTX->grps_nodes, NULL);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 
     /* invalid content */
-    YCTX->parsed_mod->version = 1; /* simulate YANG 1.0 */
+    PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
     in.current = "l {action x;} ...";
     assert_int_equal(LY_EVALID, parse_list(YCTX, NULL, (struct lysp_node **)&l));
     CHECK_LOG_CTX("Invalid keyword \"action\" as a child of \"list\" - the statement is allowed only in YANG 1.1 modules.", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)l); l = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)l); l = NULL;
 }
 
 static void
@@ -1186,14 +1195,14 @@
 {
     struct lysp_node_choice *ch = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "ch {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_choice(YCTX, NULL, (struct lysp_node**)&ch)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)ch); ch = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)ch); ch = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("default", "a", "b");
@@ -1209,14 +1218,14 @@
             "leaf-list ll {type string;} list li;mandatory true;reference test;status current;when true;m:ext;} ...";
     assert_int_equal(LY_SUCCESS, parse_choice(YCTX, NULL, (struct lysp_node **)&ch));
     CHECK_LYSP_NODE(ch, "test", 1, LYS_CONFIG_R | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "ch", 0, LYS_CHOICE, 0, "test", 1);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ch); ch = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ch); ch = NULL;
 
     /* full content - the default missing from the previous node */
     in.current = "ch {default c;case c;} ...";
     assert_int_equal(LY_SUCCESS, parse_choice(YCTX, NULL, (struct lysp_node **)&ch));
     CHECK_LYSP_NODE(ch, NULL, 0, 0, 0, "ch", 0, LYS_CHOICE, 0, NULL, 0);
     assert_string_equal("c", ch->dflt.str);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)ch); ch = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)ch); ch = NULL;
 }
 
 static void
@@ -1224,14 +1233,14 @@
 {
     struct lysp_node_case *cs = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "cs {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_case(YCTX, NULL, (struct lysp_node**)&cs)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)cs); cs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)cs); cs = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1244,13 +1253,13 @@
             "leaf-list ll {type string;} list li;reference test;status current;uses grp;when true;m:ext;} ...";
     assert_int_equal(LY_SUCCESS, parse_case(YCTX, NULL, (struct lysp_node **)&cs));
     CHECK_LYSP_NODE(cs, "test", 1, LYS_STATUS_CURR, 1, "cs", 0, LYS_CASE, 0, "test", 1);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)cs); cs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)cs); cs = NULL;
 
     /* invalid content */
     in.current = "cs {config true} ...";
     assert_int_equal(LY_EVALID, parse_case(YCTX, NULL, (struct lysp_node **)&cs));
     CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"case\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)cs); cs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)cs); cs = NULL;
 }
 
 static void
@@ -1259,9 +1268,9 @@
     struct lysp_node_anydata *any = NULL;
 
     if (kw == LY_STMT_ANYDATA) {
-        YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+        PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     } else {
-        YCTX->parsed_mod->version = 1; /* simulate YANG 1.0 */
+        PARSER_CUR_PMOD(YCTX)->version = 1; /* simulate YANG 1.0 */
     }
 
     /* invalid cardinality */
@@ -1269,7 +1278,7 @@
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_any(YCTX, kw, NULL, (struct lysp_node**)&any)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)any); any = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)any); any = NULL;
 
     TEST_DUP("config", "true", "false");
     TEST_DUP("description", "text1", "text2");
@@ -1286,7 +1295,7 @@
     uint16_t node_type = kw == LY_STMT_ANYDATA ? LYS_ANYDATA : LYS_ANYXML;
     CHECK_LYSP_NODE(any, "test", 1, LYS_CONFIG_W | LYS_STATUS_CURR | LYS_MAND_TRUE, 1, "any", 0, node_type, 0, "test", 1);
     assert_non_null(any->musts);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)any); any = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)any); any = NULL;
 }
 
 static void
@@ -1306,7 +1315,7 @@
 {
     struct lysp_node_grp *grp = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     YCTX->main_ctx = (struct lys_parser_ctx *)YCTX;
 
     /* invalid cardinality */
@@ -1314,7 +1323,7 @@
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, &grp->node); grp = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, &grp->node); grp = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1335,20 +1344,20 @@
     assert_int_equal(LYS_STATUS_CURR, grp->flags);
     ly_set_erase(&YCTX->tpdfs_nodes, NULL);
     ly_set_erase(&YCTX->grps_nodes, NULL);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, &grp->node);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, &grp->node);
     grp = NULL;
 
     /* invalid content */
     in.current = "grp {config true} ...";
     assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp));
     CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"grouping\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, &grp->node);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, &grp->node);
     grp = NULL;
 
     in.current = "grp {must 'expr'} ...";
     assert_int_equal(LY_EVALID, parse_grouping(YCTX, NULL, &grp));
     CHECK_LOG_CTX("Invalid keyword \"must\" as a child of \"grouping\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, &grp->node);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, &grp->node);
     grp = NULL;
 }
 
@@ -1358,7 +1367,7 @@
     struct lysp_node_action *rpcs = NULL;
     struct lysp_node_container *c = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     YCTX->main_ctx = (struct lys_parser_ctx *)YCTX;
 
     /* invalid cardinality */
@@ -1366,7 +1375,7 @@
     in.current = "func {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_action(YCTX, NULL, &rpcs)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)rpcs); rpcs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)rpcs); rpcs = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("input", "{leaf l1 {type empty;}} description a", "{leaf l2 {type empty;}} description a");
@@ -1411,15 +1420,15 @@
 
     ly_set_erase(&YCTX->tpdfs_nodes, NULL);
     ly_set_erase(&YCTX->grps_nodes, NULL);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)rpcs); rpcs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)rpcs); rpcs = NULL;
 
     /* invalid content */
     in.current = "func {config true} ...";
     assert_int_equal(LY_EVALID, parse_action(YCTX, NULL, &rpcs));
     CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"rpc\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)rpcs); rpcs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)rpcs); rpcs = NULL;
 
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c);
 }
 
 static void
@@ -1428,7 +1437,7 @@
     struct lysp_node_notif *notifs = NULL;
     struct lysp_node_container *c = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
     YCTX->main_ctx = (struct lys_parser_ctx *)YCTX;
 
     /* invalid cardinality */
@@ -1436,7 +1445,7 @@
     in.current = "func {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_notif(YCTX, NULL, &notifs)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)notifs); notifs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)notifs); notifs = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1464,15 +1473,15 @@
 
     ly_set_erase(&YCTX->tpdfs_nodes, NULL);
     ly_set_erase(&YCTX->grps_nodes, NULL);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)notifs); notifs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)notifs); notifs = NULL;
 
     /* invalid content */
     in.current = "ntf {config true} ...";
     assert_int_equal(LY_EVALID, parse_notif(YCTX, NULL, &notifs));
     CHECK_LOG_CTX("Invalid keyword \"config\" as a child of \"notification\".", "Line number 1.");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)notifs); notifs = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)notifs); notifs = NULL;
 
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)c);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)c);
 }
 
 static void
@@ -1480,14 +1489,14 @@
 {
     struct lysp_node_uses *u = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_uses(YCTX, NULL, (struct lysp_node**)&u)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node*)u); u = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node*)u); u = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1501,7 +1510,7 @@
     CHECK_LYSP_NODE(u, "test", 1, LYS_STATUS_CURR, 1, "grpref", 0, LYS_USES, 0, "test", 1);
     assert_non_null(u->augments);
     assert_non_null(u->refines);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)u); u = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)u); u = NULL;
 }
 
 static void
@@ -1509,14 +1518,14 @@
 {
     struct lysp_node_augment *a = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_augment(YCTX, NULL, &a)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)a); a = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)a); a = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1538,7 +1547,7 @@
     assert_non_null(a->when);
     assert_null(a->parent);
     assert_int_equal(LYS_STATUS_CURR, a->flags);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)a); a = NULL;
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)a); a = NULL;
 }
 
 static void
@@ -1546,14 +1555,14 @@
 {
     struct lysp_when *w = NULL;
 
-    YCTX->parsed_mod->version = 2; /* simulate YANG 1.1 */
+    PARSER_CUR_PMOD(YCTX)->version = 2; /* simulate YANG 1.1 */
 
     /* invalid cardinality */
 #define TEST_DUP(MEMBER, VALUE1, VALUE2) \
     in.current = "l {" MEMBER" "VALUE1";"MEMBER" "VALUE2";} ..."; \
     assert_int_equal(LY_EVALID, parse_when(YCTX, &w)); \
     CHECK_LOG_CTX("Duplicate keyword \""MEMBER"\".", "Line number 1."); \
-    FREE_MEMBER(YCTX->parsed_mod->mod->ctx, w, lysp_when_free); w = NULL;
+    FREE_MEMBER(PARSER_CUR_PMOD(YCTX)->mod->ctx, w, lysp_when_free); w = NULL;
 
     TEST_DUP("description", "text1", "text2");
     TEST_DUP("reference", "1", "2");
@@ -1567,7 +1576,7 @@
     assert_string_equal("test", w->dsc);
     assert_string_equal("test", w->ref);
     assert_non_null(w->exts);
-    FREE_MEMBER(YCTX->parsed_mod->mod->ctx, w, lysp_when_free); w = NULL;
+    FREE_MEMBER(PARSER_CUR_PMOD(YCTX)->mod->ctx, w, lysp_when_free); w = NULL;
 
     /* empty condition */
     in.current = "\"\";";
@@ -1575,7 +1584,7 @@
     CHECK_LOG_CTX("Empty argument of when statement does not make sense.", NULL);
     assert_non_null(w);
     assert_string_equal("", w->cond);
-    FREE_MEMBER(YCTX->parsed_mod->mod->ctx, w, lysp_when_free); w = NULL;
+    FREE_MEMBER(PARSER_CUR_PMOD(YCTX)->mod->ctx, w, lysp_when_free); w = NULL;
 }
 
 static void
diff --git a/tests/utests/schema/test_parser_yin.c b/tests/utests/schema/test_parser_yin.c
index b8ac15a..59353a4 100644
--- a/tests/utests/schema/test_parser_yin.c
+++ b/tests/utests/schema/test_parser_yin.c
@@ -130,17 +130,21 @@
 static int
 setup_ctx(void **state)
 {
+    struct lysp_module *pmod;
+
     /* allocate parser context */
     YCTX = calloc(1, sizeof(*YCTX));
     YCTX->format = LYS_IN_YIN;
+    ly_set_new(&YCTX->parsed_mods);
 
     /* allocate new parsed module */
-    YCTX->parsed_mod = calloc(1, sizeof *YCTX->parsed_mod);
+    pmod = calloc(1, sizeof *pmod);
+    ly_set_add(YCTX->parsed_mods, pmod, 1, NULL);
 
     /* allocate new module */
-    YCTX->parsed_mod->mod = calloc(1, sizeof *YCTX->parsed_mod->mod);
-    YCTX->parsed_mod->mod->ctx = UTEST_LYCTX;
-    YCTX->parsed_mod->mod->parsed = YCTX->parsed_mod;
+    pmod->mod = calloc(1, sizeof *pmod->mod);
+    pmod->mod->ctx = UTEST_LYCTX;
+    pmod->mod->parsed = pmod;
 
     return 0;
 }
@@ -158,7 +162,7 @@
 static int
 teardown_ctx(void **UNUSED(state))
 {
-    lys_module_free(YCTX->parsed_mod->mod);
+    lys_module_free(PARSER_CUR_PMOD(YCTX)->mod);
     yin_parser_ctx_free(YCTX);
     YCTX = NULL;
 
@@ -1216,7 +1220,7 @@
     struct lysp_submodule submod;
     struct lysp_ext_instance *exts = NULL;
 
-    lydict_insert(UTEST_LYCTX, "module-name", 0, &YCTX->parsed_mod->mod->name);
+    lydict_insert(UTEST_LYCTX, "module-name", 0, &PARSER_CUR_PMOD(YCTX)->mod->name);
 
     data = ELEMENT_WRAPPER_START
             "<belongs-to module=\"module-name\"><prefix value=\"pref\"/>"EXT_SUBELEM "</belongs-to>"
@@ -2451,7 +2455,7 @@
     struct include_meta inc_meta = {"module-name", &includes};
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<include module=\"mod\">\n"
             "    <description><text>desc</text></description>\n"
@@ -2477,7 +2481,7 @@
     includes = NULL;
 
     /* invalid combinations */
-    YCTX->parsed_mod->version = LYS_VERSION_1_0;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_0;
     data = ELEMENT_WRAPPER_START
             "<include module=\"mod\">\n"
             "    <description><text>desc</text></description>\n"
@@ -2490,7 +2494,7 @@
     FREE_ARRAY(UTEST_LYCTX, includes, lysp_include_free);
     includes = NULL;
 
-    YCTX->parsed_mod->version = LYS_VERSION_1_0;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_0;
     data = ELEMENT_WRAPPER_START
             "<include module=\"mod\">\n"
             "    <reference><text>ref</text></reference>\n"
@@ -2598,7 +2602,7 @@
     struct tree_node_meta notif_meta = {NULL, (struct lysp_node **)&notifs};
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<notification name=\"notif-name\">\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -2730,7 +2734,7 @@
     struct lysp_node_container *parsed = NULL;
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<container name=\"cont-name\">\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -2812,7 +2816,7 @@
     struct lysp_node_case *parsed = NULL;
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<case name=\"case-name\">\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -2879,7 +2883,7 @@
     struct lysp_node_choice *parsed = NULL;
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<choice name=\"choice-name\">\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -2949,7 +2953,7 @@
     struct inout_meta inout_meta = {NULL, &inout};
 
     /* max subelements */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<input>\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -2993,7 +2997,7 @@
     memset(&inout, 0, sizeof inout);
 
     /* max subelements */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<output>\n"
             "    <anydata name=\"anyd\"/>\n"
@@ -3064,7 +3068,7 @@
     uint16_t flags;
 
     /* max subelems */
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<action name=\"act\">\n"
             "    <description><text>desc</text></description>\n"
@@ -3100,7 +3104,7 @@
     lysp_node_free(UTEST_LYCTX, (struct lysp_node *)actions);
     actions = NULL;
 
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<rpc name=\"act\">\n"
             "    <description><text>desc</text></description>\n"
@@ -3148,7 +3152,7 @@
     struct lysp_node_augment *augments = NULL;
     struct tree_node_meta aug_meta = {NULL, (struct lysp_node **)&augments};
 
-    YCTX->parsed_mod->version = LYS_VERSION_1_1;
+    PARSER_CUR_PMOD(YCTX)->version = LYS_VERSION_1_1;
     data = ELEMENT_WRAPPER_START
             "<augment target-node=\"target\">\n"
             "    <action name=\"action\"/>\n"
@@ -3201,13 +3205,13 @@
     assert_string_equal(augments->actions->name, "action");
     assert_string_equal(augments->notifs->name, "notif");
     TEST_1_CHECK_LYSP_EXT_INSTANCE(&(augments->exts[0]), LY_STMT_AUGMENT);
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)augments);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)augments);
     augments = NULL;
 
     data = ELEMENT_WRAPPER_START "<augment target-node=\"target\" />" ELEMENT_WRAPPER_END;
     assert_int_equal(test_element_helper(state, data, &aug_meta, NULL, NULL), LY_SUCCESS);
     assert_string_equal(augments->nodeid, "target");
-    lysp_node_free(YCTX->parsed_mod->mod->ctx, (struct lysp_node *)augments);
+    lysp_node_free(PARSER_CUR_PMOD(YCTX)->mod->ctx, (struct lysp_node *)augments);
     augments = NULL;
 }
 
@@ -3421,15 +3425,17 @@
 static struct lysp_module *
 mod_renew(struct lys_yin_parser_ctx *ctx)
 {
-    struct ly_ctx *ly_ctx = ctx->parsed_mod->mod->ctx;
+    struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
+    struct lysp_module *pmod;
 
-    lys_module_free(ctx->parsed_mod->mod);
-    ctx->parsed_mod = calloc(1, sizeof *ctx->parsed_mod);
-    ctx->parsed_mod->mod = calloc(1, sizeof *ctx->parsed_mod->mod);
-    ctx->parsed_mod->mod->parsed = ctx->parsed_mod;
-    ctx->parsed_mod->mod->ctx = ly_ctx;
+    lys_module_free(PARSER_CUR_PMOD(ctx)->mod);
+    pmod = calloc(1, sizeof *pmod);
+    ctx->parsed_mods->objs[0] = pmod;
+    pmod->mod = calloc(1, sizeof *pmod->mod);
+    pmod->mod->parsed = pmod;
+    pmod->mod->ctx = ly_ctx;
 
-    return ctx->parsed_mod;
+    return pmod;
 }
 
 static void
@@ -3549,16 +3555,18 @@
 static struct lysp_submodule *
 submod_renew(struct lys_yin_parser_ctx *ctx, const char *belongs_to)
 {
-    struct ly_ctx *ly_ctx = ctx->parsed_mod->mod->ctx;
+    struct ly_ctx *ly_ctx = PARSER_CUR_PMOD(ctx)->mod->ctx;
+    struct lysp_submodule *submod;
 
-    lys_module_free(ctx->parsed_mod->mod);
-    ctx->parsed_mod = calloc(1, sizeof(struct lysp_submodule));
-    ctx->parsed_mod->mod = calloc(1, sizeof *ctx->parsed_mod->mod);
-    lydict_insert(ly_ctx, belongs_to, 0, &ctx->parsed_mod->mod->name);
-    ctx->parsed_mod->mod->parsed = ctx->parsed_mod;
-    ctx->parsed_mod->mod->ctx = ly_ctx;
+    lys_module_free(PARSER_CUR_PMOD(ctx)->mod);
+    submod = calloc(1, sizeof *submod);
+    ctx->parsed_mods->objs[0] = submod;
+    submod->mod = calloc(1, sizeof *submod->mod);
+    lydict_insert(ly_ctx, belongs_to, 0, &submod->mod->name);
+    submod->mod->parsed = (struct lysp_module *)submod;
+    submod->mod->ctx = ly_ctx;
 
-    return (struct lysp_submodule *)ctx->parsed_mod;
+    return submod;
 }
 
 static void
@@ -3805,7 +3813,7 @@
     struct lysp_submodule *submod = NULL;
     struct ly_in *in;
 
-    lydict_insert(UTEST_LYCTX, "a", 0, &YCTX->parsed_mod->mod->name);
+    lydict_insert(UTEST_LYCTX, "a", 0, &PARSER_CUR_PMOD(YCTX)->mod->name);
 
     data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             "<submodule name=\"asub\""
diff --git a/tests/utests/schema/test_schema_common.c b/tests/utests/schema/test_schema_common.c
index 3c78d0d..ab0d81b 100644
--- a/tests/utests/schema/test_schema_common.c
+++ b/tests/utests/schema/test_schema_common.c
@@ -976,7 +976,7 @@
         struct module_clb_list list[] = {
             {"main_c", "module main_c { yang-version 1.1; namespace urn:test:main_c; prefix mc; include sub_c_one; include sub_c_two;}"},
             {"sub_c_one", "submodule sub_c_one { yang-version 1.1; belongs-to main_c { prefix mc; } include sub_c_two;}"},
-            {"sub_c_two", "submodule sub_c_two { yang-version 1.1; belongs-to main_c { prefix mc; } }"},
+            {"sub_c_two", "submodule sub_c_two { yang-version 1.1; belongs-to main_c { prefix mc; } include sub_c_one;}"},
             {NULL, NULL}
         };
         ly_ctx_set_module_imp_clb(UTEST_LYCTX, module_clb, list);
@@ -985,7 +985,7 @@
         assert_int_equal(2, LY_ARRAY_COUNT(mod->parsed->includes));
         assert_false(mod->parsed->includes[1].injected);
         /* result is ok, but log includes the warning */
-        CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (sub_c_one) are not necessary.", NULL);
+        CHECK_LOG_CTX("YANG version 1.1 expects all includes in main module, includes in submodules (sub_c_two) are not necessary.", NULL);
     }
 }
 
diff --git a/tests/utests/types/yang_types.c b/tests/utests/types/yang_types.c
index c8540bd..2ed427c 100644
--- a/tests/utests/types/yang_types.c
+++ b/tests/utests/types/yang_types.c
@@ -101,6 +101,10 @@
     /* canonize */
     TEST_SUCCESS_XML("a", "l", "2005-02-29T23:15:15-02:00", STRING, "2005-03-01T23:15:15-02:00");
 
+    /* unknown timezone */
+    TEST_SUCCESS_XML("a", "l", "2017-02-01T00:00:00-00:00", STRING, "2017-02-01T00:00:00-00:00");
+    TEST_SUCCESS_XML("a", "l", "2021-02-29T00:00:00-00:00", STRING, "2021-03-01T00:00:00-00:00");
+
     TEST_ERROR_XML("a", "l", "2005-05-31T23:15:15.-08:00");
     CHECK_LOG_CTX("Unsatisfied pattern - \"2005-05-31T23:15:15.-08:00\" does not conform to "
             "\"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[\\+\\-]\\d{2}:\\d{2})\".",
@@ -178,6 +182,7 @@
     /* date-and-time */
     TEST_SUCCESS_LYB("a", "l", "2005-05-25T23:15:15.88888Z");
     TEST_SUCCESS_LYB("a", "l", "2005-05-31T23:15:15-08:59");
+    TEST_SUCCESS_LYB("a", "l", "2005-05-01T20:15:15-00:00");
 
     /* xpath1.0 */
     TEST_SUCCESS_LYB("a\" xmlns:aa=\"urn:tests:a", "l2", "/aa:l2[. = '4']");
diff --git a/tools/lint/common.c b/tools/lint/common.c
index 64c34dc..b41e4fe 100644
--- a/tools/lint/common.c
+++ b/tools/lint/common.c
@@ -94,7 +94,7 @@
     struct schema_features *rec = (struct schema_features *)flist;
 
     if (rec) {
-        free(rec->module);
+        free(rec->mod_name);
         if (rec->features) {
             for (uint32_t u = 0; rec->features[u]; ++u) {
                 free(rec->features[u]);
@@ -108,20 +108,19 @@
 void
 get_features(struct ly_set *fset, const char *module, const char ***features)
 {
-    static const char *all_features[] = {"*", NULL};
-
     /* get features list for this module */
     for (uint32_t u = 0; u < fset->count; ++u) {
         struct schema_features *sf = (struct schema_features *)fset->objs[u];
-        if (!strcmp(module, sf->module)) {
+        if (!strcmp(module, sf->mod_name)) {
             /* matched module - explicitly set features */
             *features = (const char **)sf->features;
+            sf->applied = 1;
             return;
         }
     }
 
-    /* features not set, enable all features by default */
-    *features = all_features;
+    /* features not set so disable all */
+    *features = NULL;
 }
 
 int
@@ -144,10 +143,10 @@
     /* fill the record */
     p = strchr(fstring, ':');
     if (!p) {
-        YLMSG_E("Invalid format of the features specification (%s)", fstring);
+        YLMSG_E("Invalid format of the features specification (%s).\n", fstring);
         return -1;
     }
-    rec->module = strndup(fstring, p - fstring);
+    rec->mod_name = strndup(fstring, p - fstring);
 
     /* start count on 2 to include terminating NULL byte */
     for (int count = 2; p; ++count) {
@@ -265,7 +264,7 @@
         ++count;
         r = realloc(vector, (count + 1) * sizeof *vector);
         if (!r) {
-            YLMSG_E("Memory allocation failed (%s:%d, %s),", __FILE__, __LINE__, strerror(errno));
+            YLMSG_E("Memory allocation failed (%s:%d, %s).\n", __FILE__, __LINE__, strerror(errno));
             free(vector);
             return -1;
         }
diff --git a/tools/lint/common.h b/tools/lint/common.h
index 2e25c09..ae37df2 100644
--- a/tools/lint/common.h
+++ b/tools/lint/common.h
@@ -48,8 +48,9 @@
  * @brief Storage for the list of the features (their names) in a specific YANG module.
  */
 struct schema_features {
-    char *module;
+    char *mod_name;
     char **features;
+    ly_bool applied;
 };
 
 /**
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 1097301..bff705a 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -50,7 +50,7 @@
     /*
      * schema
      */
-    /* set schema modules' features via --feature option (struct schema_features *) */
+    /* set schema modules' features via --features option (struct schema_features *) */
     struct ly_set schema_features;
 
     /* set of loaded schema modules (struct lys_module *) */
@@ -132,8 +132,10 @@
     printf("Options:\n"
             "  -h, --help    Show this help message and exit.\n"
             "  -v, --version Show version number and exit.\n"
-            "  -V, --verbose Show verbose messages, can be used multiple times to\n"
-            "                increase verbosity.\n");
+            "  -V, --verbose Increase libyang verbosity and show verbose messages. If specified\n"
+            "                a second time, show even debug messages.\n"
+            "  -Q, --quiet   Decrease libyang verbosity and hide warnings. If specified a second\n"
+            "                time, hide errors so no libyang messages are printed.\n");
 
     printf("  -f FORMAT, --format=FORMAT\n"
             "                Convert input into FORMAT. Supported formats: \n"
@@ -152,8 +154,11 @@
             "                explicitly specified).\n\n");
 
     printf("  -F FEATURES, --features=FEATURES\n"
-            "                Features to support, default all in all implemented modules.\n"
-            "                <modname>:[<feature>,]*\n\n");
+            "                Specific module features to support in the form <module-name>:(<feature>,)*\n"
+            "                Use <feature> '*' to enable all features of a module. This option can be\n"
+            "                specified multiple times, to enable features in multiple modules. If this\n"
+            "                option is not specified, all the features in all the implemented modules\n"
+            "                are enabled.\n\n");
 
     printf("  -i, --make-implemented\n"
             "                Make the imported modules \"referenced\" from any loaded\n"
@@ -238,7 +243,7 @@
     printf("  -G GROUPS, --debug=GROUPS\n"
             "                Enable printing of specific debugging message group\n"
             "                (nothing will be printed unless verbosity is set to debug):\n"
-            "                <group>[,<group>]* (dict, xpath)\n\n");
+            "                <group>[,<group>]* (dict, xpath, dep-sets)\n\n");
 #endif
 }
 
@@ -268,10 +273,26 @@
     }
 }
 
+static struct schema_features *
+get_features_not_applied(const struct ly_set *fset)
+{
+    for (uint32_t u = 0; u < fset->count; ++u) {
+        struct schema_features *sf = fset->objs[u];
+        if (!sf->applied) {
+            return sf;
+        }
+    }
+
+    return NULL;
+}
+
 static int
 fill_context_inputs(int argc, char *argv[], struct context *c)
 {
     struct ly_in *in;
+    struct schema_features *sf;
+    struct lys_module *mod;
+    const char *all_features[] = {"*", NULL};
 
     /* process the operational content if any */
     if (c->data_operational.path) {
@@ -293,8 +314,7 @@
             LY_ERR ret;
             uint8_t path_unset = 1; /* flag to unset the path from the searchpaths list (if not already present) */
             char *dir, *module;
-            const char **features = NULL;
-            uint16_t ctx_opts = 0;
+            const char **features;
             struct lys_module *mod;
 
             if (parse_schema_path(argv[optind + i], &dir, &module)) {
@@ -307,12 +327,10 @@
             }
 
             /* get features list for this module */
-            get_features(&c->schema_features, module, &features);
-
-            /* set imp feature flag if all should be enabled */
             if (!c->schema_features.count) {
-                ctx_opts = LY_CTX_ENABLE_IMP_FEATURES;
-                ly_ctx_set_options(c->ctx, ctx_opts);
+                features = all_features;
+            } else {
+                get_features(&c->schema_features, module, &features);
             }
 
             /* temporary cleanup */
@@ -322,11 +340,10 @@
             /* parse module */
             ret = lys_parse(c->ctx, in, format_schema, features, &mod);
             ly_ctx_unset_searchdir_last(c->ctx, path_unset);
-            ly_ctx_unset_options(c->ctx, ctx_opts);
             ly_in_free(in, 1);
             in = NULL;
             if (ret) {
-                YLMSG_E("Processing schema module from %s failed.\n", argv[optind + i]);
+                YLMSG_E("Parsing schema module \"%s\" failed.\n", argv[optind + i]);
                 goto error;
             }
 
@@ -348,6 +365,26 @@
         }
     }
 
+    /* check that all specified features were applied, apply now if possible */
+    while ((sf = get_features_not_applied(&c->schema_features))) {
+        /* try to find implemented or the latest revision of this module */
+        mod = ly_ctx_get_module_implemented(c->ctx, sf->mod_name);
+        if (!mod) {
+            mod = ly_ctx_get_module_latest(c->ctx, sf->mod_name);
+        }
+        if (!mod) {
+            YLMSG_E("Specified features not applied, module \"%s\" not loaded.\n", sf->mod_name);
+            goto error;
+        }
+
+        /* we have the module, implement it if needed and enable the specific features */
+        if (lys_set_implemented(mod, (const char **)sf->features)) {
+            YLMSG_E("Implementing module \"%s\" failed.\n", mod->name);
+            goto error;
+        }
+        sf->applied = 1;
+    }
+
     return 0;
 
 error:
@@ -372,6 +409,7 @@
         {"help",             no_argument,       NULL, 'h'},
         {"version",          no_argument,       NULL, 'v'},
         {"verbose",          no_argument,       NULL, 'V'},
+        {"quiet",            no_argument,       NULL, 'Q'},
         {"format",           required_argument, NULL, 'f'},
         {"path",             required_argument, NULL, 'p'},
         {"disable-searchdir", no_argument,      NULL, 'D'},
@@ -402,10 +440,11 @@
     c->data_parse_options = YL_DEFAULT_DATA_PARSE_OPTIONS;
     c->line_length = 0;
 
+    opterr = 0;
 #ifndef NDEBUG
-    while ((opt = getopt_long(argc, argv, "hvVf:p:DF:iP:qs:net:d:lL:o:Omy", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:OmyG:", options, &opt_index)) != -1) {
 #else
-    while ((opt = getopt_long(argc, argv, "hvVf:p:DF:iP:qs:net:d:lL:o:OmyG:", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVQf:p:DF:iP:qs:net:d:lL:o:Omy", options, &opt_index)) != -1) {
 #endif
         switch (opt) {
         case 'h': /* --help */
@@ -418,14 +457,25 @@
 
         case 'V': { /* --verbose */
             LY_LOG_LEVEL verbosity = ly_log_level(LY_LLERR);
-            ly_log_level(verbosity);
-
             if (verbosity < LY_LLDBG) {
-                ly_log_level(verbosity + 1);
+                ++verbosity;
             }
+            ly_log_level(verbosity);
             break;
         } /* case 'V' */
 
+        case 'Q': { /* --quiet */
+            LY_LOG_LEVEL verbosity = ly_log_level(LY_LLERR);
+            if (verbosity == LY_LLERR) {
+                /* turn logging off */
+                ly_log_options(LY_LOSTORE_LAST);
+            } else if (verbosity > LY_LLERR) {
+                --verbosity;
+            }
+            ly_log_level(verbosity);
+            break;
+        } /* case 'Q' */
+
         case 'f': /* --format */
             if (!strcasecmp(optarg, "yang")) {
                 c->schema_out_format = LYS_OUT_YANG;
@@ -615,6 +665,9 @@
                 } else if (!strncasecmp(ptr, "xpath", sizeof "xpath" - 1)) {
                     dbg_groups |= LY_LDGXPATH;
                     ptr += sizeof "xpath" - 1;
+                } else if (!strncasecmp(ptr, "dep-sets", sizeof "dep-sets" - 1)) {
+                    dbg_groups |= LY_LDGDEPSETS;
+                    ptr += sizeof "dep-sets" - 1;
                 }
 
                 if (ptr[0]) {
@@ -629,9 +682,17 @@
             break;
         } /* case 'G' */
 #endif
+        default:
+            YLMSG_E("Invalid option or missing argument: -%c\n", optopt);
+            return -1;
         } /* switch */
     }
 
+    /* set imp feature flag if all should be enabled */
+    if (!c->schema_features.count) {
+        options_ctx |= LY_CTX_ENABLE_IMP_FEATURES;
+    }
+
     /* libyang context */
     if (ly_ctx_new(NULL, options_ctx, &c->ctx)) {
         YLMSG_E("Unable to create libyang context.\n");