Skip to content

Commit d975237

Browse files
committed
Merge remote-tracking branch 'origin/master' into github/master
2 parents f578317 + e96d5be commit d975237

7 files changed

Lines changed: 232 additions & 18 deletions

File tree

lib/Parser/parse.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3709,19 +3709,25 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool
37093709
m_scopeCountNoAst = 0;
37103710

37113711
long* pAstSizeSave = m_pCurrentAstSize;
3712+
bool noStmtContext = false;
37123713

37133714
if (buildAST || BindDeferredPidRefs())
37143715
{
37153716
if (fDeclaration && m_scriptContext->GetConfig()->IsBlockScopeEnabled())
37163717
{
3717-
bool needsBlockNode =
3718+
noStmtContext =
37183719
(m_pstmtCur->isDeferred && m_pstmtCur->op != knopBlock) ||
37193720
(!m_pstmtCur->isDeferred && m_pstmtCur->pnodeStmt->nop != knopBlock);
37203721

3721-
if (needsBlockNode)
3722+
if (noStmtContext)
37223723
{
37233724
// We have a function declaration like "if (a) function f() {}". We didn't see
3724-
// a block scope on the way in, so we need to pretend we did.
3725+
// a block scope on the way in, so we need to pretend we did. Note that this is a syntax error
3726+
// in strict mode.
3727+
if (!this->FncDeclAllowedWithoutContext(flags))
3728+
{
3729+
Error(ERRsyntax);
3730+
}
37253731
pnodeFncBlockScope = StartParseBlock<buildAST>(PnodeBlockType::Regular, ScopeType_Block);
37263732
if (buildAST)
37273733
{
@@ -3853,7 +3859,7 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool
38533859
}
38543860

38553861
bool needScanRCurly = true;
3856-
bool result = ParseFncDeclHelper<buildAST>(pnodeFnc, pnodeFncSave, pNameHint, flags, &funcHasName, fUnaryOrParen, &needScanRCurly);
3862+
bool result = ParseFncDeclHelper<buildAST>(pnodeFnc, pnodeFncSave, pNameHint, flags, &funcHasName, fUnaryOrParen, noStmtContext, &needScanRCurly);
38573863
if (!result)
38583864
{
38593865
Assert(!pnodeFncBlockScope);
@@ -4037,6 +4043,13 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool
40374043
return pnodeFnc;
40384044
}
40394045

4046+
bool Parser::FncDeclAllowedWithoutContext(ushort flags)
4047+
{
4048+
// Statement context required for strict mode, async functions, and generators.
4049+
// Note that generators aren't detected yet when this method is called; they're checked elsewhere.
4050+
return !IsStrictMode() && !(flags & fFncAsync);
4051+
}
4052+
40404053
uint Parser::CalculateFunctionColumnNumber()
40414054
{
40424055
uint columnNumber;
@@ -4089,7 +4102,7 @@ void Parser::AppendFunctionToScopeList(bool fDeclaration, ParseNodePtr pnodeFnc)
40894102
Parse a function definition.
40904103
***************************************************************************/
40914104
template<bool buildAST>
4092-
bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool *pNeedScanRCurly)
4105+
bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly)
40934106
{
40944107
bool fDeclaration = (flags & fFncDeclaration) != 0;
40954108
bool fLambda = (flags & fFncLambda) != 0;
@@ -4120,6 +4133,13 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncPare
41204133

41214134
*pHasName = !fLambda && this->ParseFncNames<buildAST>(pnodeFnc, pnodeFncParent, flags, &lastNodeRef);
41224135

4136+
if (noStmtContext && pnodeFnc->sxFnc.IsGenerator())
4137+
{
4138+
// Generator decl not allowed outside stmt context. (We have to wait until we've parsed the '*' to
4139+
// detect generator.)
4140+
Error(ERRsyntax, pnodeFnc);
4141+
}
4142+
41234143
// switch scanner to treat 'yield' as keyword in generator functions
41244144
// or as an identifier in non-generator functions
41254145
bool fPreviousYieldIsKeyword = m_pscan->SetYieldIsKeyword(pnodeFnc && pnodeFnc->sxFnc.IsGenerator());

lib/Parser/parse.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,9 @@ class Parser
704704
template<bool buildAST> ParseNodePtr ParseFncDecl(ushort flags, LPCOLESTR pNameHint = NULL, const bool isSourceElement = false, const bool needsPIDOnRCurlyScan = false, bool resetParsingSuperRestrictionState = true, bool fUnaryOrParen = false);
705705
template<bool buildAST> bool ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, ushort flags, ParseNodePtr **pLastNodeRef);
706706
template<bool buildAST> void ParseFncFormals(ParseNodePtr pnodeFnc, ushort flags);
707-
template<bool buildAST> bool ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool *pNeedScanRCurly);
707+
template<bool buildAST> bool ParseFncDeclHelper(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly);
708708
template<bool buildAST> void ParseExpressionLambdaBody(ParseNodePtr pnodeFnc);
709+
bool FncDeclAllowedWithoutContext(ushort flags);
709710
void FinishFncDecl(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ParseNodePtr *lastNodeRef);
710711
void ParseTopLevelDeferredFunc(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, LPCOLESTR pNameHint);
711712
void ParseNestedDeferredFunc(ParseNodePtr pnodeFnc, bool fLambda, bool *pNeedScanRCurly, bool *pStrictModeTurnedOn);

lib/Runtime/Base/ScriptContext.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,17 +2821,30 @@ namespace Js
28212821
while (asmEnvIter.IsValid())
28222822
{
28232823
// we are attaching, change frame setup for asm.js frame to javascript frame
2824-
SList<AsmJsScriptFunction*> * funcList = asmEnvIter.CurrentValue();
2824+
SList<AsmJsScriptFunction *> * funcList = asmEnvIter.CurrentValue();
28252825
Assert(!funcList->Empty());
28262826
void* newEnv = AsmJsModuleInfo::ConvertFrameForJavascript(asmEnvIter.CurrentKey(), funcList->Head());
2827-
while (!funcList->Empty())
2827+
funcList->Iterate([&](AsmJsScriptFunction * func)
28282828
{
2829-
AsmJsScriptFunction* func = funcList->Pop();
28302829
func->GetEnvironment()->SetItem(0, newEnv);
2831-
func->SetModuleMemory(nullptr);
2832-
}
2830+
});
28332831
asmEnvIter.MoveNext();
28342832
}
2833+
2834+
// walk through and clean up the asm.js fields as a discrete step, because module might be multiply linked
2835+
auto asmCleanupIter = asmJsEnvironmentMap->GetIterator();
2836+
while (asmCleanupIter.IsValid())
2837+
{
2838+
SList<AsmJsScriptFunction *> * funcList = asmCleanupIter.CurrentValue();
2839+
Assert(!funcList->Empty());
2840+
funcList->Iterate([](AsmJsScriptFunction * func)
2841+
{
2842+
func->SetModuleMemory(nullptr);
2843+
func->GetFunctionBody()->ResetAsmJsInfo();
2844+
});
2845+
asmCleanupIter.MoveNext();
2846+
}
2847+
28352848
ReleaseTemporaryAllocator(tmpAlloc);
28362849
#endif
28372850
END_TRANSLATE_OOM_TO_HRESULT(hrEntryPointUpdate);

test/es6/blockscope-functionbinding.baseline

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,25 @@ Test 20: Function declaration in statement context without {}
192192
1
193193
0
194194

195+
Test 21: Function declaration in statement context without {}, strict mode
196+
197+
21.1: Syntax error
198+
21.2: Syntax error
199+
21.3: Syntax error
200+
21.4: Syntax error
201+
202+
Test 22: Function declaration in statement context without {}, illegal in sloppy mode
203+
204+
22.1: Syntax error
205+
22.2: Syntax error
206+
22.3: Syntax error
207+
22.4: Syntax error
208+
22.5: Syntax error
209+
22.6: Syntax error
210+
22.7: Syntax error
211+
22.8: Syntax error
212+
22.8: Syntax error
213+
195214
Test Global: Global scope has the same semantics for block-scoped function declarations
196215

197216
undefined

test/es6/blockscope-functionbinding.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,170 @@ print('\nTest 20: Function declaration in statement context without {}\n');
558558
function f4() { print('0'); }
559559
}
560560

561+
while (false)
562+
function f5() {}
563+
564+
for (;false;)
565+
function f6() {}
566+
567+
for (var p in {a:'a'})
568+
function f7() {}
569+
570+
for (var e of [1])
571+
function f8() {}
572+
573+
with ({})
574+
function f9() {}
575+
561576
f1();
562577
f2();
563578
f3();
564579
f4();
580+
581+
f7();
582+
f8();
583+
f9();
584+
})();
585+
586+
print('\nTest 21: Function declaration in statement context without {}, strict mode\n');
587+
(function() {
588+
"use strict";
589+
590+
// The B.3.4 exceptions are not allowed in strict mode
591+
592+
try {
593+
eval('if (true)' +
594+
' function f() { return "not allowed in strict mode"; }' +
595+
'else' +
596+
' void 0;');
597+
}
598+
catch(ex) {
599+
print('21.1: ' + ex.message);
600+
}
601+
602+
try {
603+
eval('if (true)' +
604+
' void 0;' +
605+
'else' +
606+
' function f() { return "not allowed in strict mode"; }');
607+
}
608+
catch(ex) {
609+
print('21.2: ' + ex.message);
610+
}
611+
612+
try {
613+
eval('if (true)' +
614+
' function f() { return "not allowed in strict mode"; }' +
615+
'else' +
616+
' function f() { return "not allowed in strict mode"; }');
617+
}
618+
catch(ex) {
619+
print('21.3: ' + ex.message);
620+
}
621+
622+
try {
623+
eval('if (true)' +
624+
' function f() { return "not allowed in strict mode"; }');
625+
}
626+
catch(ex) {
627+
print('21.4: ' + ex.message);
628+
}
629+
})();
630+
631+
print('\nTest 22: Function declaration in statement context without {}, illegal in sloppy mode\n');
632+
(function() {
633+
// Always illegal syntax regardless of strict mode
634+
// generator functions are GeneratorFunctionDeclaration, not FunctionDeclaration
635+
// so are also not allowed by the B.3.4 exception
636+
637+
try {
638+
eval('if (true)' +
639+
' function* f() { return "never allowed"; }' +
640+
'else' +
641+
' void 0;');
642+
}
643+
catch(ex) {
644+
print('22.1: ' + ex.message);
645+
}
646+
647+
try {
648+
eval('if (true)' +
649+
' void 0;' +
650+
'else' +
651+
' function* f() { return "never allowed"; }');
652+
}
653+
catch(ex) {
654+
print('22.2: ' + ex.message);
655+
}
656+
657+
try {
658+
eval('if (true)' +
659+
' function* f() { return "never allowed"; }' +
660+
'else' +
661+
' function* f() { return "never allowed"; }');
662+
}
663+
catch(ex) {
664+
print('22.3: ' + ex.message);
665+
}
666+
667+
try {
668+
eval('if (true)' +
669+
' function* f() { return "never allowed"; }');
670+
}
671+
catch(ex) {
672+
print('22.4: ' + ex.message);
673+
}
674+
675+
// async is ES7 but presumably will also not be FunctionDeclaration in the grammar
676+
// and so are also not allowed by the B.3.4 exception
677+
678+
try {
679+
eval('if (true)' +
680+
' async function f() { return "never allowed"; }' +
681+
'else' +
682+
' void 0;');
683+
}
684+
catch(ex) {
685+
print('22.5: ' + ex.message);
686+
}
687+
688+
try {
689+
eval('if (true)' +
690+
' void 0;' +
691+
'else' +
692+
' async function f() { return "never allowed"; }');
693+
}
694+
catch(ex) {
695+
print('22.6: ' + ex.message);
696+
}
697+
698+
try {
699+
eval('if (true)' +
700+
' async function f() { return "never allowed"; }' +
701+
'else' +
702+
' async function f() { return "never allowed"; }');
703+
}
704+
catch(ex) {
705+
print('22.7: ' + ex.message);
706+
}
707+
708+
try {
709+
eval('if (true)' +
710+
' async function f() { return "never allowed"; }' +
711+
'else' +
712+
' async function f() { return "never allowed"; }');
713+
}
714+
catch(ex) {
715+
print('22.8: ' + ex.message);
716+
}
717+
718+
try {
719+
eval('if (true)' +
720+
' async function f() { return "never allowed"; }');
721+
}
722+
catch(ex) {
723+
print('22.8: ' + ex.message);
724+
}
565725
})();
566726

567727
// Leave this test last since it is at global scope and would be awkward to place in the middle of the cleanly contained tests

test/es6/rlexe.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,20 +233,21 @@
233233
<test>
234234
<default>
235235
<files>blockscope-functionbinding.js</files>
236+
<compile-flags>-ES7AsyncAwait</compile-flags>
236237
<baseline>blockscope-functionbinding.baseline</baseline>
237238
</default>
238239
</test>
239240
<test>
240241
<default>
241242
<files>blockscope-functionbinding.js</files>
242-
<compile-flags>-force:deferparse</compile-flags>
243+
<compile-flags>-force:deferparse -ES7AsyncAwait</compile-flags>
243244
<baseline>blockscope-functionbinding.baseline</baseline>
244245
</default>
245246
</test>
246247
<test>
247248
<default>
248249
<files>blockscope-functionbinding.js</files>
249-
<compile-flags>-lic:1 -InitializeInterpreterSlotsWithInvalidStackVar</compile-flags>
250+
<compile-flags>-lic:1 -InitializeInterpreterSlotsWithInvalidStackVar -ES7AsyncAwait</compile-flags>
250251
<baseline>blockscope-functionbinding.baseline</baseline>
251252
<tags>exclude_fre</tags>
252253
</default>

test/strict/21.functionDeclaration_sm.baseline

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Return: Program.SourceElement.FunctionDeclaration
22
Return: FunctionBody.FunctionDeclaration
33
Return: Block.StatementList.Statement.FunctionDeclaration
4-
Return: IfStatement.Statement.FunctionDeclaration
5-
Return: IterationStatement(do-while).Statement.FunctionDeclaration
6-
Return: IterationStatement(while).Statement.FunctionDeclaration
7-
Return: IterationStatement(for).Statement.FunctionDeclaration
8-
Return: IterationStatement(for-in).Statement.FunctionDeclaration
4+
Exception: IfStatement.Statement.FunctionDeclaration - SyntaxError
5+
Exception: IterationStatement(do-while).Statement.FunctionDeclaration - SyntaxError
6+
Exception: IterationStatement(while).Statement.FunctionDeclaration - SyntaxError
7+
Exception: IterationStatement(for).Statement.FunctionDeclaration - SyntaxError
8+
Exception: IterationStatement(for-in).Statement.FunctionDeclaration - SyntaxError
99
Return: SourceElement.Statement.LabelledStatement.Statement.FunctionDeclaration
1010
Return: Block.Statement.LabelledStatement.Statement.FunctionDeclaration
1111
Return: SwitchStatement.CaseBlock.CaseClause.StatementList.Statement.FunctionDeclaration

0 commit comments

Comments
 (0)