Modified: trunk/JSTests/ChangeLog (258860 => 258861)
--- trunk/JSTests/ChangeLog 2020-03-23 18:10:48 UTC (rev 258860)
+++ trunk/JSTests/ChangeLog 2020-03-23 18:23:50 UTC (rev 258861)
@@ -1,3 +1,13 @@
+2020-03-23 Ross Kirsling <[email protected]>
+
+ Catch parameters must not be lexically redeclared
+ https://bugs.webkit.org/show_bug.cgi?id=208976
+
+ Reviewed by Keith Miller.
+
+ * test262/expectations.yaml:
+ Mark four test cases as passing.
+
2020-03-20 Ross Kirsling <[email protected]>
hasObservableSideEffectsForRegExpSplit doesn't check for @@match override
Modified: trunk/JSTests/test262/expectations.yaml (258860 => 258861)
--- trunk/JSTests/test262/expectations.yaml 2020-03-23 18:10:48 UTC (rev 258860)
+++ trunk/JSTests/test262/expectations.yaml 2020-03-23 18:23:50 UTC (rev 258861)
@@ -3679,12 +3679,6 @@
test/language/statements/switch/syntax/redeclaration/var-name-redeclaration-attempt-with-generator.js:
default: 'Test262: This statement should not be evaluated.'
strict mode: 'Test262: This statement should not be evaluated.'
-test/language/statements/try/early-catch-function.js:
- default: 'Test262: This statement should not be evaluated.'
- strict mode: 'Test262: This statement should not be evaluated.'
-test/language/statements/try/early-catch-lex.js:
- default: 'Test262: This statement should not be evaluated.'
- strict mode: 'Test262: This statement should not be evaluated.'
test/language/statements/while/let-array-with-newline.js:
default: 'Test262: This statement should not be evaluated.'
test/language/statements/with/let-array-with-newline.js:
Modified: trunk/Source/_javascript_Core/ChangeLog (258860 => 258861)
--- trunk/Source/_javascript_Core/ChangeLog 2020-03-23 18:10:48 UTC (rev 258860)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-03-23 18:23:50 UTC (rev 258861)
@@ -1,3 +1,28 @@
+2020-03-23 Ross Kirsling <[email protected]>
+
+ Catch parameters must not be lexically redeclared
+ https://bugs.webkit.org/show_bug.cgi?id=208976
+
+ Reviewed by Keith Miller.
+
+ From https://tc39.es/ecma262/#sec-try-statement-static-semantics-early-errors:
+ Catch : catch ( CatchParameter ) Block
+ It is a Syntax Error if any element of the BoundNames of CatchParameter
+ also occurs in the LexicallyDeclaredNames of Block.
+
+ In other words, let/const/class/function declarations in the immediate catch block scope
+ must not shadow catch parameters.
+
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseTryStatement):
+ (JSC::Parser<LexerType>::parseBlockStatement):
+ * parser/Parser.h:
+ (JSC::Scope::Scope):
+ (JSC::Scope::setIsCatchBlockScope): Added.
+ (JSC::Scope::isCatchBlockScope): Added.
+ (JSC::Parser::declareVariable):
+ (JSC::Parser::declareFunction):
+
2020-03-23 Michael Catanzaro <[email protected]>
REGRESSION(r249808): [GTK] Crash in JSC Config::permanentlyFreeze() on architecture ppc64el
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (258860 => 258861)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2020-03-23 18:10:48 UTC (rev 258860)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2020-03-23 18:23:50 UTC (rev 258861)
@@ -1779,7 +1779,8 @@
}
handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target");
matchOrFail(OPENBRACE, "Expected exception handler to be a block statement");
- catchBlock = parseBlockStatement(context);
+ constexpr bool isCatchBlock = true;
+ catchBlock = parseBlockStatement(context, isCatchBlock);
failIfFalse(catchBlock, "Unable to parse 'catch' block");
catchEnvironment = catchScope->finalizeLexicalEnvironment();
RELEASE_ASSERT(!ident || (catchEnvironment.size() == 1 && catchEnvironment.contains(ident->impl())));
@@ -1812,7 +1813,7 @@
}
template <typename LexerType>
-template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context)
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context, bool isCatchBlock)
{
ASSERT(match(OPENBRACE));
@@ -1824,6 +1825,8 @@
ScopeRef newScope = pushScope();
newScope->setIsLexicalScope();
newScope->preventVarDeclarations();
+ if (isCatchBlock)
+ newScope->setIsCatchBlockScope();
lexicalScope.setIsValid(newScope, this);
}
JSTokenLocation location(tokenLocation());
Modified: trunk/Source/_javascript_Core/parser/Parser.h (258860 => 258861)
--- trunk/Source/_javascript_Core/parser/Parser.h 2020-03-23 18:10:48 UTC (rev 258860)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2020-03-23 18:23:50 UTC (rev 258861)
@@ -176,6 +176,7 @@
, m_isLexicalScope(false)
, m_isGlobalCodeScope(false)
, m_isSimpleCatchParameterScope(false)
+ , m_isCatchBlockScope(false)
, m_isFunctionBoundary(false)
, m_isValidStrictMode(true)
, m_hasArguments(false)
@@ -299,6 +300,9 @@
void setIsSimpleCatchParameterScope() { m_isSimpleCatchParameterScope = true; }
bool isSimpleCatchParameterScope() { return m_isSimpleCatchParameterScope; }
+ void setIsCatchBlockScope() { m_isCatchBlockScope = true; }
+ bool isCatchBlockScope() { return m_isCatchBlockScope; }
+
void setIsLexicalScope()
{
m_isLexicalScope = true;
@@ -829,6 +833,7 @@
bool m_isLexicalScope;
bool m_isGlobalCodeScope;
bool m_isSimpleCatchParameterScope;
+ bool m_isCatchBlockScope;
bool m_isFunctionBoundary;
bool m_isValidStrictMode;
bool m_hasArguments;
@@ -1280,7 +1285,11 @@
if (!m_lexer->isReparsingFunction() && m_statementDepth == 1 && (hasDeclaredParameter(*ident) || hasDeclaredVariable(*ident)))
return DeclarationResult::InvalidDuplicateDeclaration;
- return currentLexicalDeclarationScope()->declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration, importType);
+ ScopeRef scope = currentLexicalDeclarationScope();
+ if (scope->isCatchBlockScope() && scope.containingScope()->hasLexicallyDeclaredVariable(*ident))
+ return DeclarationResult::InvalidDuplicateDeclaration;
+
+ return scope->declareLexicalVariable(ident, type == DeclarationType::ConstDeclaration, importType);
}
std::pair<DeclarationResultMask, ScopeRef> declareFunction(const Identifier* ident)
@@ -1295,6 +1304,11 @@
return std::make_pair(variableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), variableScope);
}
+ bool declareAsVar = false;
+ ScopeRef lexicalVariableScope = currentLexicalDeclarationScope();
+ if (lexicalVariableScope->isCatchBlockScope() && lexicalVariableScope.containingScope()->hasLexicallyDeclaredVariable(*ident))
+ return std::make_pair(DeclarationResult::InvalidDuplicateDeclaration, lexicalVariableScope);
+
if (!strictMode()) {
ASSERT(currentScope()->isFunction() || closestParentOrdinaryFunctionNonLexicalScope()->isEvalContext());
@@ -1306,9 +1320,7 @@
// there are is a let/class/const with the same name). Note that this mean we only do the "var" hoisting
// binding if the block evaluates. For example, this means we wont won't perform the binding if it's inside
// the untaken branch of an if statement.
- bool declareAsVar = false;
bool isSloppyModeHoistingCandidate = true;
- ScopeRef lexicalVariableScope = currentLexicalDeclarationScope();
ScopeRef varScope = currentVariableScope();
varScope->addSloppyModeHoistableFunctionCandidate(ident);
ASSERT(varScope != lexicalVariableScope);
@@ -1315,9 +1327,7 @@
return std::make_pair(lexicalVariableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope);
}
- bool declareAsVar = false;
bool isSloppyModeHoistingCandidate = false;
- ScopeRef lexicalVariableScope = currentLexicalDeclarationScope();
return std::make_pair(lexicalVariableScope->declareFunction(ident, declareAsVar, isSloppyModeHoistingCandidate), lexicalVariableScope);
}
@@ -1635,7 +1645,7 @@
template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&, bool allowFunctionDeclarationAsStatement);
template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
- template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&, bool isCatchBlock = false);
template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&, ExpressionErrorClassifier&);
template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);