tree schema CHANGE plugin record in parsed extensions
diff --git a/src/parser_yang.c b/src/parser_yang.c
index d0b2ea1..3a1fe17 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -39,6 +39,7 @@
 
 /**
  * @brief Insert WORD into the libyang context's dictionary and store as TARGET.
+ *
  * @param[in] CTX yang parser context to access libyang context.
  * @param[in] BUF buffer in case the word is not a constant and can be inserted directly (zero-copy)
  * @param[out] TARGET variable where to store the pointer to the inserted value.
@@ -51,44 +52,61 @@
 
 /**
  * @brief Read from the IN structure COUNT items. Also updates the indent value in yang parser context
+ *
  * @param[in] CTX yang parser context to update its indent value.
  * @param[in] COUNT number of items for which the DATA pointer is supposed to move on.
  */
 #define MOVE_INPUT(CTX, COUNT) ly_in_skip((CTX)->in, COUNT);(CTX)->indent+=COUNT
 
 /**
- * @brief Loop through all substatements.
+ * @brief Loop through all substatements. Starts a for loop and ::YANG_READ_SUBSTMT_NEXT_ITER must be used at its end.
  *
  * @param[in] CTX yang parser context for logging.
  * @param[out] KW YANG keyword read.
  * @param[out] WORD Pointer to the keyword itself.
  * @param[out] WORD_LEN Length of the keyword.
  * @param[out] RET Variable for error storing.
- * @param[in] SUC_CMD Command is applied if a semicolon is found, so no
- * substatements are available. It is expected to contain a return or goto command.
- * @param[in] ERR_CMD Command is applied if an error occurs before loop through
- * substatements. It is expected to contain return or goto command.
- *
- * @return In case there are no substatements or a fatal error encountered.
+ * @param[in] ERR_LABEL Label to go to on error.
  */
-#define YANG_READ_SUBSTMT_FOR(CTX, KW, WORD, WORD_LEN, RET, SUC_CMD, ERR_CMD) \
+#define YANG_READ_SUBSTMT_FOR_GOTO(CTX, KW, WORD, WORD_LEN, RET, ERR_LABEL) \
+    ly_bool __loop_end = 0; \
     if ((RET = get_keyword(CTX, &KW, &WORD, &WORD_LEN))) { \
-        ERR_CMD; \
+        goto ERR_LABEL; \
     } \
     if (KW == LY_STMT_SYNTAX_SEMICOLON) { \
-        SUC_CMD; \
-    } \
-    if (KW != LY_STMT_SYNTAX_LEFT_BRACE) { \
+        __loop_end = 1; \
+    } else if (KW != LY_STMT_SYNTAX_LEFT_BRACE) { \
         LOGVAL_PARSER(CTX, LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", expected \";\" or \"{\".", ly_stmt2str(KW)); \
         RET = LY_EVALID; \
-        ERR_CMD; \
+        goto ERR_LABEL; \
+    } else { \
+        YANG_READ_SUBSTMT_NEXT_ITER(CTX, KW, WORD, WORD_LEN, NULL, RET, ERR_LABEL); \
     } \
-    for (RET = get_keyword(CTX, &KW, &WORD, &WORD_LEN); \
-            !RET && (KW != LY_STMT_SYNTAX_RIGHT_BRACE); \
-            RET = get_keyword(CTX, &KW, &WORD, &WORD_LEN))
+    while (!__loop_end)
 
-LY_ERR parse_container(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent,
-        struct lysp_node **siblings);
+/**
+ * @brief Next iteration of ::YANG_READ_SUBSTMT_FOR_GOTO loop.
+ *
+ * @param[in] CTX yang parser context for logging.
+ * @param[out] KW YANG keyword read.
+ * @param[out] WORD Pointer to the keyword itself.
+ * @param[out] WORD_LEN Length of the keyword.
+ * @param[in] EXTS Final extension instance array to store.
+ * @param[out] RET Variable for error storing.
+ * @param[in] ERR_LABEL Label to go to on error.
+ */
+#define YANG_READ_SUBSTMT_NEXT_ITER(CTX, KW, WORD, WORD_LEN, EXTS, RET, ERR_LABEL) \
+    if ((RET = get_keyword(CTX, &KW, &WORD, &WORD_LEN))) { \
+        goto ERR_LABEL; \
+    } \
+    if (KW == LY_STMT_SYNTAX_RIGHT_BRACE) { \
+        if (EXTS && (RET = ly_set_add(&(CTX)->ext_inst, (EXTS), 1, NULL))) { \
+            goto ERR_LABEL; \
+        } \
+        __loop_end = 1; \
+    }
+
+LY_ERR parse_container(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_uses(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_choice(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_case(struct lys_yang_parser_ctx *ctx, struct lysp_node *parent, struct lysp_node **siblings);
@@ -106,7 +124,6 @@
  * @param[in,out] buf Buffer to use, can be moved by realloc().
  * @param[in,out] buf_len Current size of the buffer.
  * @param[in,out] buf_used Currently used characters of the buffer.
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -144,7 +161,6 @@
  * 0 - colon not yet found (no prefix)
  * 1 - \p c is the colon character
  * 2 - prefix already processed, now processing the identifier
- *
  * @return LY_ERR values.
  */
 LY_ERR
@@ -300,7 +316,6 @@
  * @param[out] buf_len Length of the dynamically-allocated buffer \p word_b.
  * @param[in] indent Current indent (number of YANG spaces). Needed for correct multi-line string
  * indenation in the final quoted string.
- *
  * @return LY_ERR values.
  */
 static LY_ERR
@@ -888,8 +903,9 @@
     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) {
-        LY_CHECK_RET(parse_ext_substmt(ctx, child_kw, word, word_len, &stmt->child));
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, child_kw, word, word_len, ret, cleanup) {
+        LY_CHECK_GOTO(ret = parse_ext_substmt(ctx, child_kw, word, word_len, &stmt->child), cleanup)
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, child_kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -941,8 +957,9 @@
     e->parent_stmt = insubstmt;
     e->parent_stmt_index = insubstmt_index;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
-        LY_CHECK_RET(parse_ext_substmt(ctx, kw, word, word_len, &e->child));
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
+        LY_CHECK_GOTO(ret = parse_ext_substmt(ctx, kw, word, word_len, &e->child), cleanup)
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -982,7 +999,7 @@
     /* store value and spend buf if allocated */
     INSERT_WORD_GOTO(ctx, buf, *value, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, substmt_index, exts));
@@ -991,6 +1008,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -1033,7 +1051,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YANG_VERSION, 0, exts));
@@ -1042,7 +1060,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yang-version");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1078,7 +1099,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_PREFIX:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, prefix, Y_IDENTIF_ARG, exts));
@@ -1090,14 +1111,16 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "belongs-to");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
-checks:
+
     /* mandatory substatements */
     if (!*prefix) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "belongs-to");
         return LY_EVALID;
     }
+
+cleanup:
     return ret;
 }
 
@@ -1136,7 +1159,7 @@
     strncpy(rev, word, word_len);
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REVISION_DATE, 0, exts));
@@ -1145,7 +1168,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision-date");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1181,7 +1207,7 @@
         return LY_EVALID;
     }
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             PARSER_CHECK_STMTVER2_RET(ctx, "description", "include");
@@ -1201,6 +1227,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "include");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, inc->exts, ret, cleanup);
     }
 
 cleanup:
@@ -1231,7 +1258,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, imp->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_PREFIX:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_PREFIX, 0, &imp->prefix, Y_IDENTIF_ARG, &imp->exts));
@@ -1255,10 +1282,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "import");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, imp->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     LY_CHECK_ERR_RET(!imp->prefix, LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "prefix", "import"), LY_EVALID);
 
@@ -1297,7 +1323,7 @@
     strncpy(rev->date, word, word_len);
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &rev->dsc, Y_STR_ARG, &rev->exts));
@@ -1312,7 +1338,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "revision");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, rev->exts, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1344,7 +1373,7 @@
     LY_CHECK_RET(get_argument(ctx, arg, NULL, &word, &buf, &word_len));
 
     INSERT_WORD_GOTO(ctx, buf, *item, word, word_len, ret, cleanup);
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*texts) - 1, exts));
@@ -1353,6 +1382,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -1388,7 +1418,7 @@
 
     INSERT_WORD_GOTO(ctx, buf, item->str, word, word_len, ret, cleanup);
     item->mod = PARSER_CUR_PMOD(ctx);
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, substmt, LY_ARRAY_COUNT(*qnames) - 1, exts));
@@ -1397,6 +1427,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(substmt));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -1439,7 +1470,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_CONFIG, 0, exts));
@@ -1448,7 +1479,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "config");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1488,7 +1522,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MANDATORY, 0, exts));
@@ -1497,7 +1531,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "mandatory");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1524,7 +1561,7 @@
     CHECK_NONEMPTY(ctx, word_len, ly_stmt2str(restr_kw));
     INSERT_WORD_GOTO(ctx, buf, restr->arg.str, word, word_len, ret, cleanup);
     restr->arg.mod = PARSER_CUR_PMOD(ctx);
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
@@ -1545,6 +1582,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(restr_kw));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, restr->exts, ret, cleanup);
     }
 
 cleanup:
@@ -1607,7 +1645,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_STATUS, 0, exts));
@@ -1616,7 +1654,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "status");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -1651,7 +1692,7 @@
     CHECK_NONEMPTY(ctx, word_len, "when");
     INSERT_WORD_GOTO(ctx, buf, when->cond, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto cleanup, goto cleanup) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &when->dsc, Y_STR_ARG, &when->exts), cleanup);
@@ -1667,6 +1708,7 @@
             ret = LY_EVALID;
             goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, when->exts, ret, cleanup);
     }
 
 cleanup:
@@ -1708,7 +1750,7 @@
     INSERT_WORD_GOTO(ctx, buf, any->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &any->flags, &any->exts));
@@ -1741,6 +1783,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(any_kw));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, any->exts, ret, cleanup);
     }
 
 cleanup:
@@ -1763,7 +1806,7 @@
         struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word, *ptr;
+    char *buf = NULL, *word, *ptr;
     size_t word_len;
     long long int num = 0;
     unsigned long long int unum = 0;
@@ -1771,7 +1814,8 @@
 
     if (*flags & LYS_SET_VALUE) {
         LOGVAL_PARSER(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(val_kw));
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     *flags |= LYS_SET_VALUE;
 
@@ -1780,7 +1824,8 @@
 
     if (!word_len || (word[0] == '+') || ((word[0] == '0') && (word_len > 1)) || ((val_kw == LY_STMT_POSITION) && !strncmp(word, "-0", 2))) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     errno = 0;
@@ -1788,46 +1833,51 @@
         num = strtoll(word, &ptr, LY_BASE_DEC);
         if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
             LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-            goto error;
+            ret = LY_EVALID;
+            goto cleanup;
         }
     } else {
         unum = strtoull(word, &ptr, LY_BASE_DEC);
         if (unum > UINT64_C(4294967295)) {
             LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-            goto error;
+            ret = LY_EVALID;
+            goto cleanup;
         }
     }
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, ly_stmt2str(val_kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     if (errno == ERANGE) {
         LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, ly_stmt2str(val_kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     if (val_kw == LY_STMT_VALUE) {
         *value = num;
     } else {
         *value = unum;
     }
-    free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, val_kw == LY_STMT_VALUE ? LY_STMT_VALUE : LY_STMT_POSITION, 0, exts));
+            ret = parse_ext(ctx, word, word_len, val_kw == LY_STMT_VALUE ? LY_STMT_VALUE : LY_STMT_POSITION, 0, exts);
+            LY_CHECK_GOTO(ret, cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(val_kw));
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
-    return ret;
 
-error:
+cleanup:
     free(buf);
-    return LY_EVALID;
+    return ret;
 }
 
 /**
@@ -1860,7 +1910,7 @@
     INSERT_WORD_GOTO(ctx, buf, enm->name, word, word_len, ret, cleanup);
     CHECK_UNIQUENESS(ctx, *enums, name, ly_stmt2str(enum_kw), enm->name);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &enm->dsc, Y_STR_ARG, &enm->exts));
@@ -1892,6 +1942,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(enum_kw));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, enm->exts, ret, cleanup);
     }
 
 cleanup:
@@ -1911,7 +1962,7 @@
 parse_type_fracdigits(struct lys_yang_parser_ctx *ctx, uint8_t *fracdig, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word, *ptr;
+    char *buf = NULL, *word, *ptr;
     size_t word_len;
     unsigned long long int num;
     enum ly_stmt kw;
@@ -1922,12 +1973,12 @@
     }
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if (!word_len || (word[0] == '0') || !isdigit(word[0])) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     errno = 0;
@@ -1935,27 +1986,31 @@
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "fraction-digits");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     if ((errno == ERANGE) || (num > LY_TYPE_DEC64_FD_MAX)) {
         LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "fraction-digits");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     *fracdig = num;
-    free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_FRACTION_DIGITS, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_FRACTION_DIGITS, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "fraction-digits");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -1974,7 +2029,7 @@
         struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word;
+    char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
@@ -1985,27 +2040,31 @@
     *flags |= LYS_SET_REQINST;
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if ((word_len == ly_strlen_const("true")) && !strncmp(word, "true", word_len)) {
         *reqinst = 1;
     } else if ((word_len != ly_strlen_const("false")) || strncmp(word, "false", word_len)) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "require-instance");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
-    free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_REQUIRE_INSTANCE, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_REQUIRE_INSTANCE, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "require-instance");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -2022,7 +2081,7 @@
 parse_type_pattern_modifier(struct lys_yang_parser_ctx *ctx, const char **pat, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word;
+    char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
@@ -2032,35 +2091,40 @@
     }
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if ((word_len != ly_strlen_const("invert-match")) || strncmp(word, "invert-match", word_len)) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "modifier");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
-    free(buf);
 
     /* replace the value in the dictionary */
     buf = malloc(strlen(*pat) + 1);
-    LY_CHECK_ERR_RET(!buf, LOGMEM(PARSER_CTX(ctx)), LY_EMEM);
+    LY_CHECK_ERR_GOTO(!buf, LOGMEM(PARSER_CTX(ctx)); ret = LY_EMEM, cleanup);
     strcpy(buf, *pat);
     lydict_remove(PARSER_CTX(ctx), *pat);
 
     assert(buf[0] == LYSP_RESTR_PATTERN_ACK);
     buf[0] = LYSP_RESTR_PATTERN_NACK;
-    LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, pat));
+    LY_CHECK_GOTO(ret = lydict_insert_zc(PARSER_CTX(ctx), buf, pat), cleanup);
+    buf = NULL;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MODIFIER, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MODIFIER, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "modifier");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -2102,7 +2166,7 @@
     LY_CHECK_RET(lydict_insert_zc(PARSER_CTX(ctx), buf, &restr->arg.str));
     restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &restr->dsc, Y_STR_ARG, &restr->exts));
@@ -2127,7 +2191,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "pattern");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, restr->exts, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -2161,7 +2228,7 @@
     /* set module */
     type->pmod = PARSER_CUR_PMOD(ctx);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_BASE:
             LY_CHECK_RET(parse_text_fields(ctx, LY_STMT_BASE, &type->bases, Y_PREF_IDENTIF_ARG, &type->exts));
@@ -2241,6 +2308,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "type");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, type->exts, ret, cleanup);
     }
 
 cleanup:
@@ -2274,7 +2342,7 @@
     INSERT_WORD_GOTO(ctx, buf, leaf->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &leaf->flags, &leaf->exts));
@@ -2317,10 +2385,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "leaf");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, leaf->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     if (!leaf->type.name) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf");
@@ -2345,7 +2412,7 @@
 parse_maxelements(struct lys_yang_parser_ctx *ctx, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word, *ptr;
+    char *buf = NULL, *word, *ptr;
     size_t word_len;
     unsigned long long int num;
     enum ly_stmt kw;
@@ -2357,12 +2424,12 @@
     *flags |= LYS_SET_MAX;
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if (!word_len || (word[0] == '0') || ((word[0] != 'u') && !isdigit(word[0]))) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     if (ly_strncmp("unbounded", word, word_len)) {
@@ -2371,13 +2438,13 @@
         /* we have not parsed the whole argument */
         if ((size_t)(ptr - word) != word_len) {
             LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "max-elements");
-            free(buf);
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
         if ((errno == ERANGE) || (num > UINT32_MAX)) {
             LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "max-elements");
-            free(buf);
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
 
         *max = num;
@@ -2387,16 +2454,21 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MAX_ELEMENTS, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MAX_ELEMENTS, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "max-elements");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -2414,7 +2486,7 @@
 parse_minelements(struct lys_yang_parser_ctx *ctx, uint32_t *min, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word, *ptr;
+    char *buf = NULL, *word, *ptr;
     size_t word_len;
     unsigned long long int num;
     enum ly_stmt kw;
@@ -2426,12 +2498,12 @@
     *flags |= LYS_SET_MIN;
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if (!word_len || !isdigit(word[0]) || ((word[0] == '0') && (word_len > 1))) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     errno = 0;
@@ -2439,27 +2511,31 @@
     /* we have not parsed the whole argument */
     if ((size_t)(ptr - word) != word_len) {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "min-elements");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     if ((errno == ERANGE) || (num > UINT32_MAX)) {
         LOGVAL_PARSER(ctx, LY_VCODE_OOB, word_len, word, "min-elements");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     *min = num;
-    free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_MIN_ELEMENTS, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_MIN_ELEMENTS, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "min-elements");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -2476,7 +2552,7 @@
 parse_orderedby(struct lys_yang_parser_ctx *ctx, uint16_t *flags, struct lysp_ext_instance **exts)
 {
     LY_ERR ret = LY_SUCCESS;
-    char *buf, *word;
+    char *buf = NULL, *word;
     size_t word_len;
     enum ly_stmt kw;
 
@@ -2486,7 +2562,7 @@
     }
 
     /* get value */
-    LY_CHECK_RET(get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len));
+    LY_CHECK_GOTO(ret = get_argument(ctx, Y_STR_ARG, NULL, &word, &buf, &word_len), cleanup);
 
     if ((word_len == ly_strlen_const("system")) && !strncmp(word, "system", word_len)) {
         *flags |= LYS_ORDBY_SYSTEM;
@@ -2494,21 +2570,25 @@
         *flags |= LYS_ORDBY_USER;
     } else {
         LOGVAL_PARSER(ctx, LY_VCODE_INVAL, word_len, word, "ordered-by");
-        free(buf);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
-    free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
-            LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_ORDERED_BY, 0, exts));
+            LY_CHECK_GOTO(ret = parse_ext(ctx, word, word_len, LY_STMT_ORDERED_BY, 0, exts), cleanup);
             break;
         default:
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "ordered-by");
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
+    free(buf);
     return ret;
 }
 
@@ -2539,7 +2619,7 @@
     INSERT_WORD_GOTO(ctx, buf, llist->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &llist->flags, &llist->exts));
@@ -2588,10 +2668,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "llist");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, llist->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     if (!llist->type.name) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "leaf-list");
@@ -2626,7 +2705,7 @@
     CHECK_NONEMPTY(ctx, word_len, "refine");
     INSERT_WORD_GOTO(ctx, buf, rf->nodeid, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &rf->flags, &rf->exts));
@@ -2666,6 +2745,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "refine");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, rf->exts, ret, cleanup);
     }
 
 cleanup:
@@ -2696,7 +2776,7 @@
     INSERT_WORD_GOTO(ctx, buf, tpdf->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         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));
@@ -2724,10 +2804,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "typedef");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, tpdf->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     if (!tpdf->type.name) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "type", "typedef");
@@ -2774,7 +2853,7 @@
     inout_p->parent = parent;
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_ANYDATA:
             PARSER_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
@@ -2817,15 +2896,15 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), ly_stmt2str(inout_kw));
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, inout_p->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     if (!inout_p->child) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
         return LY_EVALID;
     }
 
+cleanup:
     return ret;
 }
 
@@ -2854,7 +2933,7 @@
     act->nodetype = parent ? LYS_ACTION : LYS_RPC;
     act->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts));
@@ -2889,10 +2968,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, act->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* always initialize inout, they are technically present (needed for later deviations/refines) */
     if (!act->input.nodetype) {
         act->input.nodetype = LYS_INPUT;
@@ -2934,7 +3012,7 @@
     notif->nodetype = LYS_NOTIF;
     notif->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts));
@@ -2991,6 +3069,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "notification");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, notif->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3022,7 +3101,7 @@
     grp->nodetype = LYS_GROUPING;
     grp->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts));
@@ -3080,10 +3159,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "grouping");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, grp->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* store data for collision check */
     if (parent) {
         assert(ctx->main_ctx);
@@ -3120,7 +3198,7 @@
     aug->nodetype = LYS_AUGMENT;
     aug->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts));
@@ -3181,6 +3259,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "augment");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, aug->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3214,7 +3293,7 @@
     INSERT_WORD_GOTO(ctx, buf, uses->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts));
@@ -3245,6 +3324,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "uses");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, uses->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3278,7 +3358,7 @@
     INSERT_WORD_GOTO(ctx, buf, cas->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &cas->dsc, Y_STR_ARG, &cas->exts));
@@ -3327,6 +3407,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "case");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, cas->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3360,7 +3441,7 @@
     INSERT_WORD_GOTO(ctx, buf, choice->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &choice->flags, &choice->exts));
@@ -3421,6 +3502,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "choice");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, choice->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3454,7 +3536,7 @@
     INSERT_WORD_GOTO(ctx, buf, cont->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &cont->flags, &cont->exts));
@@ -3527,6 +3609,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "container");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, cont->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3560,7 +3643,7 @@
     INSERT_WORD_GOTO(ctx, buf, list->name, word, word_len, ret, cleanup);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             LY_CHECK_RET(parse_config(ctx, &list->flags, &list->exts));
@@ -3645,6 +3728,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "list");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, list->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3687,7 +3771,7 @@
     }
     free(buf);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_EXTENSION_INSTANCE:
             LY_CHECK_RET(parse_ext(ctx, word, word_len, LY_STMT_YIN_ELEMENT, 0, exts));
@@ -3697,7 +3781,10 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "yin-element");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
+
+cleanup:
     return ret;
 }
 
@@ -3728,7 +3815,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, *argument, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_YIN_ELEMENT:
             LY_CHECK_RET(parse_yinelement(ctx, flags, exts));
@@ -3740,6 +3827,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "argument");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, NULL, ret, cleanup);
     }
 
 cleanup:
@@ -3769,7 +3857,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, ex->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ex->dsc, Y_STR_ARG, &ex->exts));
@@ -3790,6 +3878,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "extension");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, ex->exts, ret, cleanup);
     }
 
 cleanup:
@@ -3883,7 +3972,7 @@
     }
     d->mod = dev_mod;
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto cleanup, goto cleanup) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_CONFIG:
             switch (dev_mod) {
@@ -4011,6 +4100,7 @@
             ret = LY_EVALID;
             goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, d->exts, ret, cleanup);
     }
 
 cleanup:
@@ -4050,7 +4140,7 @@
     CHECK_NONEMPTY(ctx, word_len, "deviation");
     INSERT_WORD_GOTO(ctx, buf, dev->nodeid, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, goto cleanup) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_GOTO(ret = parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &dev->dsc, Y_STR_ARG, &dev->exts), cleanup);
@@ -4069,10 +4159,9 @@
             ret = LY_EVALID;
             goto cleanup;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, dev->exts, ret, cleanup);
     }
-    LY_CHECK_GOTO(ret, cleanup);
 
-checks:
     /* mandatory substatements */
     if (!dev->deviates) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "deviate", "deviation");
@@ -4111,7 +4200,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, feat->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &feat->dsc, Y_STR_ARG, &feat->exts));
@@ -4132,6 +4221,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "feature");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, feat->exts, ret, cleanup);
     }
 
 cleanup:
@@ -4161,7 +4251,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, ident->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, return LY_SUCCESS, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
         switch (kw) {
         case LY_STMT_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, LY_STMT_DESCRIPTION, 0, &ident->dsc, Y_STR_ARG, &ident->exts));
@@ -4190,6 +4280,7 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "identity");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, ident->exts, ret, cleanup);
     }
 
 cleanup:
@@ -4220,7 +4311,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, mod->mod->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
 
 #define CHECK_ORDER(SECTION) \
         if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
@@ -4381,10 +4472,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "module");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, mod->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     if (!mod->mod->ns) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "namespace", "module");
@@ -4430,7 +4520,7 @@
     LY_CHECK_RET(get_argument(ctx, Y_IDENTIF_ARG, NULL, &word, &buf, &word_len));
     INSERT_WORD_GOTO(ctx, buf, submod->name, word, word_len, ret, cleanup);
 
-    YANG_READ_SUBSTMT_FOR(ctx, kw, word, word_len, ret, goto checks, return ret) {
+    YANG_READ_SUBSTMT_FOR_GOTO(ctx, kw, word, word_len, ret, cleanup) {
 
 #define CHECK_ORDER(SECTION) \
         if (mod_stmt > SECTION) {LOGVAL_PARSER(ctx, LY_VCODE_INORD, ly_stmt2str(kw), ly_stmt2str(prev_kw)); return LY_EVALID;}mod_stmt = SECTION
@@ -4591,10 +4681,9 @@
             LOGVAL_PARSER(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "submodule");
             return LY_EVALID;
         }
+        YANG_READ_SUBSTMT_NEXT_ITER(ctx, kw, word, word_len, submod->exts, ret, cleanup);
     }
-    LY_CHECK_RET(ret);
 
-checks:
     /* mandatory substatements */
     if (!submod->prefix) {
         LOGVAL_PARSER(ctx, LY_VCODE_MISSTMT, "belongs-to", "submodule");
diff --git a/src/parser_yin.c b/src/parser_yin.c
index 1e201b0..964fdd9 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -674,7 +674,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_PATTERN, NULL, &restr->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_PATTERN, NULL, &restr->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, restr->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -719,7 +724,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FRACTION_DIGITS, NULL, &type->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FRACTION_DIGITS, NULL, &type->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -751,7 +761,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ENUM, NULL, &en->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ENUM, NULL, &en->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, en->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -781,7 +796,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BIT, NULL, &en->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BIT, NULL, &en->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, en->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -811,7 +831,9 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, value, arg_val_type, kw));
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -898,7 +920,12 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REQUIRE_INSTANCE, NULL, &type->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REQUIRE_INSTANCE, NULL, &type->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -940,7 +967,9 @@
     modified_val[0] = LYSP_RESTR_PATTERN_NACK;
     LY_CHECK_RET(lydict_insert_zc(ctx->xmlctx->ctx, modified_val, pat));
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MODIFIER, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MODIFIER, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -968,7 +997,12 @@
     LY_CHECK_RET(yin_parse_attribute(ctx, arg_type, &restr->arg.str, Y_STR_ARG, restr_kw));
     restr->arg.mod = PARSER_CUR_PMOD(ctx);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr_kw, NULL, &restr->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), restr_kw, NULL, &restr->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, restr->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1084,22 +1118,25 @@
 static LY_ERR
 yin_parse_value_pos(struct lys_yin_parser_ctx *ctx, enum ly_stmt kw, struct lysp_type_enum *enm)
 {
-    assert(kw == LY_STMT_POSITION || kw == LY_STMT_VALUE);
+    LY_ERR ret = LY_SUCCESS;
     const char *temp_val = NULL;
     char *ptr;
     long long int num = 0;
     unsigned long long int unum = 0;
 
+    assert(kw == LY_STMT_POSITION || kw == LY_STMT_VALUE);
+
     /* set value flag */
     enm->flags |= LYS_SET_VALUE;
 
     /* get attribute value */
-    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, kw));
+    LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+    LY_CHECK_GOTO(ret = yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, kw), cleanup);
     if (!temp_val || (temp_val[0] == '\0') || (temp_val[0] == '+') ||
             ((temp_val[0] == '0') && (temp_val[1] != '\0')) || ((kw == LY_STMT_POSITION) && !strcmp(temp_val, "-0"))) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     /* convert value */
@@ -1108,23 +1145,27 @@
         num = strtoll(temp_val, &ptr, LY_BASE_DEC);
         if ((num < INT64_C(-2147483648)) || (num > INT64_C(2147483647))) {
             LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
-            goto error;
+            ret = LY_EVALID;
+            goto cleanup;
         }
     } else {
         unum = strtoull(temp_val, &ptr, LY_BASE_DEC);
         if (unum > UINT64_C(4294967295)) {
             LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
-            goto error;
+            ret = LY_EVALID;
+            goto cleanup;
         }
     }
     /* check if whole argument value was converted */
     if (*ptr != '\0') {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", ly_stmt2str(kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     if (errno == ERANGE) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", ly_stmt2str(kw));
-        goto error;
+        ret = LY_EVALID;
+        goto cleanup;
     }
     /* save correctly ternary operator can't be used because num and unum have different signes */
     if (kw == LY_STMT_VALUE) {
@@ -1132,18 +1173,20 @@
     } else {
         enm->value = unum;
     }
-    lydict_remove(ctx->xmlctx->ctx, temp_val);
 
     /* parse subelements */
     struct yin_subelement subelems[] = {
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, &enm->exts);
+    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), kw, NULL, &enm->exts), cleanup);
 
-error:
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_GOTO(ret = ly_set_add(&ctx->ext_inst, enm->exts, 1, NULL), cleanup);
+
+cleanup:
     lydict_remove(ctx->xmlctx->ctx, temp_val);
-    return LY_EVALID;
+    return ret;
 }
 
 /**
@@ -1174,7 +1217,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, belongsto);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BELONGS_TO, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_BELONGS_TO, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1203,7 +1248,9 @@
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, elem_type));
 
     /* parse content */
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), elem_type, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), elem_type, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1227,7 +1274,9 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NONE, NULL, Y_MAYBE_STR_ARG, LY_STMT_ERROR_MESSAGE));
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ERROR_MESSAGE, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ERROR_MESSAGE, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1279,7 +1328,12 @@
 
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, &type->name, Y_PREF_IDENTIF_ARG, LY_STMT_TYPE));
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_TYPE, NULL, &type->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_TYPE, NULL, &type->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, type->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1295,6 +1349,7 @@
 static LY_ERR
 yin_parse_maxelements(struct lys_yin_parser_ctx *ctx, uint32_t *max, uint16_t *flags, struct lysp_ext_instance **exts)
 {
+    LY_ERR ret = LY_SUCCESS;
     const char *temp_val = NULL;
     char *ptr;
     unsigned long long int num;
@@ -1303,12 +1358,12 @@
     };
 
     *flags |= LYS_SET_MAX;
-    LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
-    LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MAX_ELEMENTS));
+    LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
+    LY_CHECK_GOTO(ret = yin_parse_attribute(ctx, YIN_ARG_VALUE, &temp_val, Y_STR_ARG, LY_STMT_MAX_ELEMENTS), cleanup);
     if (!temp_val || (temp_val[0] == '\0') || (temp_val[0] == '0') || ((temp_val[0] != 'u') && !isdigit(temp_val[0]))) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
-        lydict_remove(ctx->xmlctx->ctx, temp_val);
-        return LY_EVALID;
+        ret = LY_EVALID;
+        goto cleanup;
     }
 
     if (strcmp(temp_val, "unbounded")) {
@@ -1316,18 +1371,22 @@
         num = strtoull(temp_val, &ptr, LY_BASE_DEC);
         if (*ptr != '\0') {
             LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_YIN, temp_val, "value", "max-elements");
-            lydict_remove(ctx->xmlctx->ctx, temp_val);
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
         if ((errno == ERANGE) || (num > UINT32_MAX)) {
             LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_OOB_YIN, temp_val, "value", "max-elements");
-            lydict_remove(ctx->xmlctx->ctx, temp_val);
-            return LY_EVALID;
+            ret = LY_EVALID;
+            goto cleanup;
         }
         *max = num;
     }
+
+    LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MAX_ELEMENTS, NULL, exts), cleanup);
+
+cleanup:
     lydict_remove(ctx->xmlctx->ctx, temp_val);
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MAX_ELEMENTS, NULL, exts);
+    return ret;
 }
 
 /**
@@ -1374,7 +1433,9 @@
     }
     *min = num;
     lydict_remove(ctx->xmlctx->ctx, temp_val);
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MIN_ELEMENTS, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MIN_ELEMENTS, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1454,7 +1515,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ORDERED_BY, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ORDERED_BY, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1492,7 +1555,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), any_kw, NULL, &any->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), any_kw, NULL, &any->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, any->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1533,7 +1601,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_LEAF, NULL, &leaf->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_LEAF, NULL, &leaf->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, leaf->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1578,6 +1651,9 @@
 
     LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_LEAF_LIST, NULL, &llist->exts));
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, llist->exts, 1, NULL));
+
     /* check invalid combination of subelements */
     if ((llist->min) && (llist->dflts)) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INCHILDSTMSCOMB_YIN, "min-elements", "default", "leaf-list");
@@ -1624,6 +1700,9 @@
 
     LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_TYPEDEF, NULL, &tpdf->exts));
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, tpdf->exts, 1, NULL));
+
     /* store data for collision check */
     if (typedef_meta->parent) {
         assert(ctx->main_ctx);
@@ -1669,7 +1748,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REFINE, NULL, &rf->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REFINE, NULL, &rf->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, rf->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1709,6 +1793,9 @@
 
     LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_USES, NULL, &uses->exts));
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, uses->exts, 1, NULL));
+
     return LY_SUCCESS;
 }
 
@@ -1747,7 +1834,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION, NULL, &rev->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION, NULL, &rev->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, rev->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1785,7 +1877,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_INCLUDE, NULL, &inc->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_INCLUDE, NULL, &inc->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, inc->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1813,7 +1910,9 @@
     strcpy(rev, temp_rev);
     lydict_remove(ctx->xmlctx->ctx, temp_rev);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION_DATE, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_REVISION_DATE, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1847,7 +1946,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_CONFIG, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_CONFIG, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1881,7 +1982,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_version);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YANG_VERSION, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YANG_VERSION, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1912,6 +2015,10 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_MODULE, &imp->name, Y_IDENTIF_ARG, LY_STMT_IMPORT));
     LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_IMPORT, NULL, &imp->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, imp->exts, 1, NULL));
+
     /* check prefix validity */
     LY_CHECK_RET(lysp_check_prefix((struct lys_parser_ctx *)ctx, *imp_meta->imports, imp_meta->prefix, &imp->prefix), LY_EVALID);
 
@@ -1949,7 +2056,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MANDATORY, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_MANDATORY, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -1985,7 +2094,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, value);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_STATUS, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_STATUS, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2016,7 +2127,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_WHEN, NULL, &when->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_WHEN, NULL, &when->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, when->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2051,7 +2167,9 @@
     }
     lydict_remove(ctx->xmlctx->ctx, temp_val);
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YIN_ELEMENT, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_YIN_ELEMENT, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2074,7 +2192,9 @@
     LY_CHECK_RET(lyxml_ctx_next(ctx->xmlctx));
     LY_CHECK_RET(yin_parse_attribute(ctx, YIN_ARG_NAME, arg_meta->argument, Y_IDENTIF_ARG, LY_STMT_ARGUMENT));
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ARGUMENT, NULL, exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_ARGUMENT, NULL, exts));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2103,7 +2223,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0}
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_EXTENSION, NULL, &ex->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_EXTENSION, NULL, &ex->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, ex->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2135,7 +2260,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FEATURE, NULL, &feat->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_FEATURE, NULL, &feat->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, feat->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2168,7 +2298,12 @@
         {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
     };
 
-    return yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_IDENTITY, NULL, &ident->exts);
+    LY_CHECK_RET(yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_IDENTITY, NULL, &ident->exts));
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, ident->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2226,6 +2361,9 @@
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, list->exts, 1, NULL));
+
     if (list->max && (list->min > list->max)) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_INVAL_MINMAX, list->min, list->max);
         return LY_EVALID;
@@ -2283,6 +2421,9 @@
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, notif->exts, 1, NULL));
+
     return LY_SUCCESS;
 }
 
@@ -2333,6 +2474,9 @@
     ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_GROUPING, NULL, &grp->exts);
     subelems_deallocator(subelems_size, subelems);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, grp->exts, 1, NULL));
+
     /* store data for collision check */
     if (!ret && grp->parent) {
         assert(ctx->main_ctx);
@@ -2392,8 +2536,12 @@
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
     ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CONTAINER, NULL, &cont->exts);
     subelems_deallocator(subelems_size, subelems);
+    LY_CHECK_RET(ret);
 
-    return ret;
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, cont->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2439,8 +2587,12 @@
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
     ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CASE, NULL, &cas->exts);
     subelems_deallocator(subelems_size, subelems);
+    LY_CHECK_RET(ret);
 
-    return ret;
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, cas->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2490,6 +2642,11 @@
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
     ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_CHOICE, NULL, &choice->exts);
     subelems_deallocator(subelems_size, subelems);
+    LY_CHECK_RET(ret);
+
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, choice->exts, 1, NULL));
+
     return ret;
 }
 
@@ -2536,6 +2693,9 @@
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, inout_meta->inout_p->exts, 1, NULL));
+
     if (!inout_meta->inout_p->child) {
         LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LY_VCODE_MISSTMT, "data-def-stmt", ly_stmt2str(inout_kw));
         return LY_EVALID;
@@ -2648,8 +2808,12 @@
             LY_STMT_EXTENSION_INSTANCE, NULL, 0));
     ret = yin_parse_content(ctx, subelems, subelems_size, LY_STMT_AUGMENT, NULL, &aug->exts);
     subelems_deallocator(subelems_size, subelems);
+    LY_CHECK_RET(ret);
 
-    return ret;
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, aug->exts, 1, NULL));
+
+    return LY_SUCCESS;
 }
 
 /**
@@ -2718,7 +2882,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d_add->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d->exts);
 
     } else if (dev_mod == LYS_DEV_REPLACE) {
         d_rpl = calloc(1, sizeof *d_rpl);
@@ -2737,7 +2901,7 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems),  LY_STMT_DEVIATE, NULL, &d_rpl->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems),  LY_STMT_DEVIATE, NULL, &d->exts);
 
     } else {
         d_del = calloc(1, sizeof *d_del);
@@ -2751,10 +2915,13 @@
             {LY_STMT_EXTENSION_INSTANCE, NULL, 0},
         };
 
-        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d_del->exts);
+        ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATE, NULL, &d->exts);
     }
     LY_CHECK_GOTO(ret, cleanup);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_GOTO(ret = ly_set_add(&ctx->ext_inst, d->exts, 1, NULL), cleanup);
+
     d->mod = dev_mod;
     /* insert into siblings */
     LY_LIST_INSERT(deviates, d, next);
@@ -2796,6 +2963,9 @@
 
     LY_CHECK_GOTO(ret = yin_parse_content(ctx, subelems, ly_sizeofarray(subelems), LY_STMT_DEVIATION, NULL, &dev->exts), cleanup);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_GOTO(ret = ly_set_add(&ctx->ext_inst, dev->exts, 1, NULL), cleanup);
+
 cleanup:
     if (ret) {
         lysp_deviation_free(&fctx, dev);
@@ -3578,7 +3748,7 @@
         LY_CHECK_GOTO(ret = lyxml_ctx_next(ctx->xmlctx), cleanup);
     }
 
-    /* mandatory subelemnts are checked only after whole element was succesfully parsed */
+    /* mandatory subelements are checked only after whole element was succesfully parsed */
     LY_CHECK_RET(yin_check_subelem_mandatory_constraint(ctx, subelem_info, subelem_info_size, current_element));
 
 cleanup:
@@ -3638,6 +3808,9 @@
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, mod->exts, 1, NULL));
+
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
     dup = ly_ctx_get_submodule_latest(ctx->xmlctx->ctx, mod->mod->name);
@@ -3702,6 +3875,9 @@
     subelems_deallocator(subelems_size, subelems);
     LY_CHECK_RET(ret);
 
+    /* store extension instance array (no realloc anymore) to find the plugin records and finish parsing */
+    LY_CHECK_RET(ly_set_add(&ctx->ext_inst, submod->exts, 1, NULL));
+
     /* submodules share the namespace with the module names, so there must not be
      * a submodule of the same name in the context, no need for revision matching */
     dup = ly_ctx_get_submodule_latest(ctx->xmlctx->ctx, submod->name);
diff --git a/src/plugins.c b/src/plugins.c
index 28fcd0e..d62da1c 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -147,8 +147,8 @@
     return plugins->objs[*index - 1];
 }
 
-void *
-lyplg_find(enum LYPLG type, const char *module, const char *revision, const char *name)
+static void *
+lyplg_record_find(enum LYPLG type, const char *module, const char *revision, const char *name)
 {
     uint32_t i = 0;
     struct lyplg_record *item;
@@ -164,13 +164,28 @@
                 continue;
             }
 
-            return &item->plugin;
+            return item;
         }
     }
 
     return NULL;
 }
 
+struct lyplg_type *
+lyplg_type_plugin_find(const char *module, const char *revision, const char *name)
+{
+    struct lyplg_record *record;
+
+    record = lyplg_record_find(LYPLG_TYPE, module, revision, name);
+    return record ? &((struct lyplg_type_record *)record)->plugin : NULL;
+}
+
+struct lyplg_ext_record *
+lyplg_ext_record_find(const char *module, const char *revision, const char *name)
+{
+    return lyplg_record_find(LYPLG_EXTENSION, module, revision, name);
+}
+
 /**
  * @brief Insert the provided extension plugin records into the internal set of extension plugins for use by libyang.
  *
diff --git a/src/plugins_exts/metadata.h b/src/plugins_exts/metadata.h
index 56d5cb6..f9dbd12 100644
--- a/src/plugins_exts/metadata.h
+++ b/src/plugins_exts/metadata.h
@@ -26,8 +26,6 @@
 #define ANNOTATION_SUBSTMT_DSC     4 /**< index for the LY_STMT_DSC substatement in annotation's ::lysc_ext_instance.substmts */
 #define ANNOTATION_SUBSTMT_REF     5 /**< index for the LY_STMT_REF substatement in annotation's ::lysc_ext_instance.substmts */
 
-#define LYEXT_PLUGIN_INTERNAL_ANNOTATION "ietf-yang-metadata", "2016-08-05", "annotation"
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/plugins_internal.h b/src/plugins_internal.h
index 2a95e86..d13db16 100644
--- a/src/plugins_internal.h
+++ b/src/plugins_internal.h
@@ -1,9 +1,10 @@
 /**
  * @file plugins_internal.h
  * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @author Michal Vasko <mvasko@cesnet.cz>
  * @brief internal functions to support extension and type plugins.
  *
- * Copyright (c) 2019-2021 CESNET, z.s.p.o.
+ * Copyright (c) 2019-2022 CESNET, z.s.p.o.
  *
  * This source code is licensed under BSD 3-Clause License (the "License").
  * You may not use this file except in compliance with the License.
@@ -59,17 +60,26 @@
 void lyplg_clean(void);
 
 /**
- * @brief Find the plugin matching the provided attributes.
+ * @brief Find a type plugin.
  *
- * @param[in] type Type of the plugin to find (type or extension)
- * @param[in] module Name of the module where the type/extension is defined. Must not be NULL, in case of plugins for
+ * @param[in] module Name of the module where the type is defined. Must not be NULL, in case of plugins for
  * built-in types, the module is "".
- * @param[in] revision The revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches
+ * @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches
  * only the plugins with NULL revision specified.
- * @param[in] name Name of the type/extension which the plugin implements.
- * @return NULL if the plugin matching the restrictions is not present.
- * @return Pointer to the matching ::lyplg_ext or ::lyplg_type according to the plugin's @p type.
+ * @param[in] name Name of the type which the plugin implements.
+ * @return Found type plugin, NULL if none found.
  */
-void *lyplg_find(enum LYPLG type, const char *module, const char *revision, const char *name);
+struct lyplg_type *lyplg_type_plugin_find(const char *module, const char *revision, const char *name);
+
+/**
+ * @brief Find an extension plugin.
+ *
+ * @param[in] module Name of the module where the extension is defined.
+ * @param[in] revision Revision of the module for which the plugin is implemented. NULL is not a wildcard, it matches
+ * only the plugins with NULL revision specified.
+ * @param[in] name Name of the extension which the plugin implements.
+ * @return Found extension record, NULL if none found.
+ */
+struct lyplg_ext_record *lyplg_ext_record_find(const char *module, const char *revision, const char *name);
 
 #endif /* LY_PLUGINS_INTERNAL_H_ */
diff --git a/src/schema_compile.c b/src/schema_compile.c
index 8eb550f..3fdb37d 100644
--- a/src/schema_compile.c
+++ b/src/schema_compile.c
@@ -52,7 +52,8 @@
  * @brief Fill in the prepared compiled extensions definition structure according to the parsed extension definition.
  */
 static LY_ERR
-lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p, struct lysc_ext **ext)
+lys_compile_extension(struct lysc_ctx *ctx, const struct lys_module *ext_mod, struct lysp_ext *ext_p,
+        const struct lyplg_ext_record *record, struct lysc_ext **ext)
 {
     LY_ERR ret = LY_SUCCESS;
 
@@ -74,8 +75,7 @@
         lysc_update_path(ctx, NULL, NULL);
 
         /* find extension definition plugin */
-        (*ext)->plugin = lyplg_find(LYPLG_EXTENSION, (*ext)->module->name,
-                (*ext)->module->revision, (*ext)->name);
+        (*ext)->plugin = record ? (struct lyplg_ext *)&record->plugin : NULL;
     }
 
     *ext = ext_p->compiled;
@@ -104,7 +104,7 @@
     lysc_update_path(ctx, NULL, ext_p->name);
 
     LY_CHECK_GOTO(ret = lysp_ext_find_definition(ctx->ctx, ext_p, &ext_mod, &ext_def), cleanup);
-    LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, ext_def, &ext->def), cleanup);
+    LY_CHECK_GOTO(ret = lys_compile_extension(ctx, ext_mod, ext_def, ext_p->record, &ext->def), cleanup);
 
     if (ext_def->argname) {
         LY_CHECK_GOTO(ret = lysp_ext_instance_resolve_argument(ctx->ctx, ext_p, ext_def), cleanup);
diff --git a/src/schema_compile_node.c b/src/schema_compile_node.c
index 10bcd22..a935907 100644
--- a/src/schema_compile_node.c
+++ b/src/schema_compile_node.c
@@ -2130,7 +2130,7 @@
         }
 
         /* try to find loaded user type plugins */
-        plugin = lyplg_find(LYPLG_TYPE, tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
+        plugin = lyplg_type_plugin_find(tctx->tpdf->type.pmod->mod->name, tctx->tpdf->type.pmod->mod->revision,
                 tctx->tpdf->name);
         if (!plugin && base) {
             /* use the base type implementation if available */
@@ -2138,7 +2138,7 @@
         }
         if (!plugin) {
             /* use the internal built-in type implementation */
-            plugin = lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
+            plugin = lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]);
         }
         assert(plugin);
 
@@ -2184,7 +2184,7 @@
     if (type_p->flags || !base || (basetype == LY_TYPE_LEAFREF)) {
         /* get restrictions from the node itself */
         (*type)->basetype = basetype;
-        (*type)->plugin = base ? base->plugin : lyplg_find(LYPLG_TYPE, "", NULL, ly_data_type2str[basetype]);
+        (*type)->plugin = base ? base->plugin : lyplg_type_plugin_find("", NULL, ly_data_type2str[basetype]);
         LY_ATOMIC_INC_BARRIER((*type)->refcount);
         ret = lys_compile_type_(ctx, context_pnode, context_flags, context_name, type_p, basetype, NULL, base, type);
         LY_CHECK_GOTO(ret, cleanup);
diff --git a/src/tree_data.c b/src/tree_data.c
index a40d4c4..e416ea0 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -958,7 +958,7 @@
     assert((parent || meta) && mod);
 
     LY_ARRAY_FOR(mod->compiled->exts, u) {
-        if ((mod->compiled->exts[u].def->plugin == lyplg_find(LYPLG_EXTENSION, LYEXT_PLUGIN_INTERNAL_ANNOTATION)) &&
+        if (!strncmp(mod->compiled->exts[u].def->plugin->id, "libyang 2 - metadata", 20) &&
                 !ly_strncmp(mod->compiled->exts[u].argument, name, name_len)) {
             /* we have the annotation definition */
             ant = &mod->compiled->exts[u];
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 000c115..b0be387 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -37,6 +37,7 @@
 #include "parser_internal.h"
 #include "parser_schema.h"
 #include "path.h"
+#include "plugins_internal.h"
 #include "schema_compile.h"
 #include "schema_compile_amend.h"
 #include "schema_features.h"
@@ -1250,8 +1251,16 @@
     return ret;
 }
 
+/**
+ * @brief Resolve (find) all imported and included modules.
+ *
+ * @param[in] pctx Parser context.
+ * @param[in] pmod Parsed module to resolve.
+ * @param[out] new_mods Set with all the newly loaded modules.
+ * @return LY_ERR value.
+ */
 static LY_ERR
-lys_resolve_import_include(struct lys_parser_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
+lysp_resolve_import_include(struct lys_parser_ctx *pctx, struct lysp_module *pmod, struct ly_set *new_mods)
 {
     struct lysp_import *imp;
     LY_ARRAY_COUNT_TYPE u, v;
@@ -1284,6 +1293,45 @@
     return LY_SUCCESS;
 }
 
+/**
+ * @brief Resolve (find) all extension instance records and finish their parsing.
+ *
+ * @param[in] pctx Parse context with all the parsed extension instances.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lysp_resolve_ext_instance_records(struct lys_parser_ctx *pctx)
+{
+    struct lysp_ext_instance *exts, *ext;
+    const struct lys_module *mod;
+    const char *ptr;
+    uint32_t i;
+    LY_ARRAY_COUNT_TYPE u;
+
+    for (i = 0; i < pctx->ext_inst.count; ++i) {
+        exts = pctx->ext_inst.objs[i];
+        LY_ARRAY_FOR(exts, u) {
+            ext = &exts[u];
+
+            /* find the extension (definition) module */
+            ptr = strchr(ext->name, ':');
+            assert(ptr);
+            mod = ly_resolve_prefix(PARSER_CTX(pctx), ext->name, ptr - ext->name, ext->format, ext->prefix_data);
+            if (!mod) {
+                LOGVAL(PARSER_CTX(pctx), LYVE_SYNTAX, "Unknown prefix \"%*.s\" used for an extension instance.",
+                        (int)(ptr - ext->name), ext->name);
+                return LY_ENOTFOUND;
+            }
+
+            /* find the extension record, if any */
+            ++ptr;
+            ext->record = lyplg_ext_record_find(mod->name, mod->revision, ptr);
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
 LY_ERR
 lys_parse_submodule(struct ly_ctx *ctx, struct ly_in *in, LYS_INFORMAT format, struct lys_parser_ctx *main_ctx,
         LY_ERR (*custom_check)(const struct ly_ctx *, struct lysp_module *, struct lysp_submodule *, void *),
@@ -1350,7 +1398,10 @@
     lys_parser_fill_filepath(ctx, in, &submod->filepath);
 
     /* resolve imports and includes */
-    LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), error);
+    LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, (struct lysp_module *)submod, new_mods), error);
+
+    /* resolve extension instance plugin records */
+    LY_CHECK_GOTO(ret = lysp_resolve_ext_instance_records(pctx), error);
 
     if (format == LYS_IN_YANG) {
         yang_parser_ctx_free(yangctx);
@@ -1383,7 +1434,7 @@
  * @return LY_ERR on error.
  */
 static LY_ERR
-lys_parsed_add_internal_ietf_netconf(struct lysp_module *mod)
+lysp_add_internal_ietf_netconf(struct lysp_module *mod)
 {
     struct lysp_ext_instance *ext_p;
     struct lysp_stmt *stmt;
@@ -1551,7 +1602,7 @@
  * @return LY_ERR on error.
  */
 static LY_ERR
-lys_parsed_add_internal_ietf_netconf_with_defaults(struct lysp_module *mod)
+lysp_add_internal_ietf_netconf_with_defaults(struct lysp_module *mod)
 {
     struct lysp_ext_instance *ext_p;
     struct lysp_stmt *stmt;
@@ -1724,9 +1775,9 @@
 
     /* add internal data in case specific modules were parsed */
     if (!strcmp(mod->name, "ietf-netconf")) {
-        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf(mod->parsed), cleanup);
+        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf(mod->parsed), cleanup);
     } else if (!strcmp(mod->name, "ietf-netconf-with-defaults")) {
-        LY_CHECK_GOTO(ret = lys_parsed_add_internal_ietf_netconf_with_defaults(mod->parsed), cleanup);
+        LY_CHECK_GOTO(ret = lysp_add_internal_ietf_netconf_with_defaults(mod->parsed), cleanup);
     }
 
     /* add the module into newly created module set, will also be freed from there on any error */
@@ -1739,7 +1790,10 @@
     ctx->change_count++;
 
     /* resolve includes and all imports */
-    LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
+    LY_CHECK_GOTO(ret = lysp_resolve_import_include(pctx, mod->parsed, new_mods), cleanup);
+
+    /* resolve extension instance plugin records */
+    LY_CHECK_GOTO(ret = lysp_resolve_ext_instance_records(pctx), cleanup);
 
     /* check name collisions */
     LY_CHECK_GOTO(ret = lysp_check_dup_typedefs(pctx, mod->parsed), cleanup);
@@ -1753,8 +1807,6 @@
     /* compile identities */
     LY_CHECK_GOTO(ret = lys_compile_identities(mod), cleanup);
 
-    /* success */
-
 cleanup:
     if (ret && (ret != LY_EEXIST)) {
         if (mod && mod->name) {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index c6d9eec..f23c6fb 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -546,6 +546,7 @@
     LY_ARRAY_COUNT_TYPE parent_stmt_index;  /**< in case the instance is in a substatement, this identifies
                                                  the index of that substatement in its [sized array](@ref sizedarrays) (if any) */
     uint16_t flags;                         /**< LYS_INTERNAL value (@ref snodeflags) */
+    const struct lyplg_ext_record *record;  /**< extension defintion plugin record, if any */
 };
 
 /**
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 34f1a22..77f9751 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -1496,6 +1496,7 @@
             ly_set_erase(&ctx->grps_nodes, NULL);
         }
         assert(!ctx->tpdfs_nodes.count && !ctx->grps_nodes.count);
+        ly_set_erase(&ctx->ext_inst, 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);
@@ -1513,6 +1514,7 @@
             ly_set_erase(&ctx->grps_nodes, NULL);
         }
         assert(!ctx->tpdfs_nodes.count && !ctx->grps_nodes.count);
+        ly_set_erase(&ctx->ext_inst, 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);
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index e90920a..e16f815 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -149,6 +149,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 ly_set ext_inst;          /**< parsed extension instances to finish parsing */
     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,
@@ -164,6 +165,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 ly_set ext_inst;          /**< parsed extension instances to finish parsing */
     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,
@@ -182,6 +184,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 ly_set ext_inst;          /**< parsed extension instances to finish parsing */
     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,