diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index a57ce22d0..9e487ab4e 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -823,7 +823,6 @@ void scanner_cleanup (parser_context_t *context_p); bool scanner_is_context_needed (parser_context_t *context_p, parser_check_context_type_t check_type); #if ENABLED (JERRY_ESNEXT) -bool scanner_scope_find_let_declaration (parser_context_t *context_p, lexer_lit_location_t *literal_p); bool scanner_try_scan_new_target (parser_context_t *context_p); void scanner_check_variables (parser_context_t *context_p); #endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index f8aed0980..ac5aa559e 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1992,7 +1992,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags |= PARSER_LEXICAL_BLOCK_NEEDED; } - if ((parse_opts & ECMA_PARSE_EVAL) == 0) + if (!(parse_opts & ECMA_PARSE_EVAL)) { scanner_check_variables (&context); } diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 2f8840e4d..cb7d9a954 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -14,6 +14,7 @@ */ #include "ecma-helpers.h" +#include "ecma-lex-env.h" #include "jcontext.h" #include "js-parser-internal.h" #include "js-scanner-internal.h" @@ -385,6 +386,85 @@ scanner_seek (parser_context_t *context_p) /**< context */ context_p->next_scanner_info_p = prev_p->next_p; } /* scanner_seek */ +#if ENABLED (JERRY_ESNEXT) + +/** + * Find any let/const declaration of a given literal. + * + * @return true - if the literal is found, false - otherwise + */ +static bool +scanner_scope_find_lexical_declaration (parser_context_t *context_p, /**< context */ + lexer_lit_location_t *literal_p) /**< literal */ +{ + ecma_string_t *name_p; + uint32_t flags = context_p->global_status_flags; + + if (!(flags & ECMA_PARSE_EVAL) + || (!(flags & ECMA_PARSE_DIRECT_EVAL) && (context_p->status_flags & PARSER_IS_STRICT))) + { + return false; + } + + if (JERRY_LIKELY (!literal_p->has_escape)) + { + name_p = ecma_new_ecma_string_from_utf8 (literal_p->char_p, literal_p->length); + } + else + { + uint8_t *destination_p = (uint8_t *) scanner_malloc (context_p, literal_p->length); + + lexer_convert_ident_to_cesu8 (destination_p, literal_p->char_p, literal_p->length); + + name_p = ecma_new_ecma_string_from_utf8 (destination_p, literal_p->length); + scanner_free (destination_p, literal_p->length); + } + + ecma_object_t *lex_env_p; + + if (flags & ECMA_PARSE_DIRECT_EVAL) + { + lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p; + + while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) + { + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p != NULL && ecma_is_property_enumerable (*property_p)) + { + ecma_deref_ecma_string (name_p); + return true; + } + } + + JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); + lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); + } + } + else + { + lex_env_p = ecma_get_global_scope (ecma_builtin_get_global ()); + } + + if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) + { + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); + + if (property_p != NULL && ecma_is_property_enumerable (*property_p)) + { + ecma_deref_ecma_string (name_p); + return true; + } + } + + ecma_deref_ecma_string (name_p); + return false; +} /* scanner_scope_find_lexical_declaration */ + +#endif /* ENABLED (JERRY_ESNEXT) */ + /** * Push a new literal pool. * @@ -694,9 +774,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ if ((status_flags & SCANNER_LITERAL_POOL_FUNCTION) && (type & SCANNER_LITERAL_IS_LOCAL_FUNC) == SCANNER_LITERAL_IS_FUNC) { - if (prev_literal_pool_p == NULL - && (context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) - && scanner_scope_find_let_declaration (context_p, literal_p)) + if (prev_literal_pool_p == NULL && scanner_scope_find_lexical_declaration (context_p, literal_p)) { literal_p->type = 0; continue; @@ -1504,65 +1582,6 @@ scanner_detect_eval_call (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ESNEXT) -/** - * Find a let/const declaration of a given literal. - * - * @return true - if the literal is found, false - otherwise - */ -bool -scanner_scope_find_let_declaration (parser_context_t *context_p, /**< context */ - lexer_lit_location_t *literal_p) /**< literal */ -{ - ecma_string_t *name_p; - - if (JERRY_LIKELY (!literal_p->has_escape)) - { - name_p = ecma_new_ecma_string_from_utf8 (literal_p->char_p, literal_p->length); - } - else - { - uint8_t *destination_p = (uint8_t *) scanner_malloc (context_p, literal_p->length); - - lexer_convert_ident_to_cesu8 (destination_p, literal_p->char_p, literal_p->length); - - name_p = ecma_new_ecma_string_from_utf8 (destination_p, literal_p->length); - scanner_free (destination_p, literal_p->length); - } - - ecma_object_t *lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p; - - while (lex_env_p->type_flags_refs & ECMA_OBJECT_FLAG_BLOCK) - { - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) - { - ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - - if (property_p != NULL && ecma_is_property_enumerable (*property_p)) - { - ecma_deref_ecma_string (name_p); - return true; - } - } - - JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); - lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); - } - - if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) - { - ecma_property_t *property_p = ecma_find_named_property (lex_env_p, name_p); - - if (property_p != NULL && ecma_is_property_enumerable (*property_p)) - { - ecma_deref_ecma_string (name_p); - return true; - } - } - - ecma_deref_ecma_string (name_p); - return false; -} /* scanner_scope_find_let_declaration */ - /** * Throws an error for invalid var statements. */ @@ -1642,8 +1661,7 @@ scanner_detect_invalid_var (parser_context_t *context_p, /**< context */ } } - if ((context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) - && scanner_scope_find_let_declaration (context_p, var_literal_p)) + if (scanner_scope_find_lexical_declaration (context_p, var_literal_p)) { scanner_raise_redeclaration_error (context_p); } @@ -2072,7 +2090,7 @@ scanner_is_context_needed (parser_context_t *context_p, /**< context */ if (JERRY_UNLIKELY (check_type == PARSER_CHECK_GLOBAL_CONTEXT) && (type == SCANNER_STREAM_TYPE_VAR - || (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL)) + || (type == SCANNER_STREAM_TYPE_FUNC && !(context_p->global_status_flags & ECMA_PARSE_EVAL)) || is_import)) { continue; @@ -2768,8 +2786,8 @@ scanner_create_variables (parser_context_t *context_p, /**< context */ { #if ENABLED (JERRY_ESNEXT) literal.char_p -= data_p[1]; - if (!(context_p->global_status_flags & ECMA_PARSE_DIRECT_EVAL) - || !scanner_scope_find_let_declaration (context_p, &literal)) + + if (!scanner_scope_find_lexical_declaration (context_p, &literal)) { func_init_opcode = CBC_CREATE_VAR_FUNC_EVAL; diff --git a/tests/jerry/es.next/regression-test-issue-4149.js b/tests/jerry/es.next/regression-test-issue-4149.js new file mode 100644 index 000000000..602964ad8 --- /dev/null +++ b/tests/jerry/es.next/regression-test-issue-4149.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +let x; +try { + (0,eval)('var x'); + assert(false) +} catch (e) { + assert(e instanceof SyntaxError) +} + +(0,eval)('function x() {};'); + diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index e6bcc830b..298306eb1 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -390,7 +390,6 @@ -