Skip to content

Commit

Permalink
Fix 'ref' parsing crash (#39233)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson committed Oct 18, 2019
1 parent 490904b commit 02d1b3c
Show file tree
Hide file tree
Showing 8 changed files with 432 additions and 146 deletions.
22 changes: 16 additions & 6 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,8 @@ internal AttributeArgumentListSyntax ParseAttributeArgumentList()
argNodes.Add(this.ParseAttributeArgument());

// comma + argument or end?
while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseParenToken)
{
Expand Down Expand Up @@ -7545,7 +7546,8 @@ private void ParseForStatementExpressionList(ref SyntaxToken startToken, Separat
list.Add(this.ParseExpressionCore());

// additional arguments
while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseParenToken || this.CurrentToken.Kind == SyntaxKind.SemicolonToken)
{
Expand Down Expand Up @@ -9223,6 +9225,10 @@ private ExpressionSyntax ParseTerm(Precedence precedence)
case SyntaxKind.DelegateKeyword:
expr = this.ParseAnonymousMethodExpression();
break;
case SyntaxKind.RefKeyword:
// ref is not expected to appear in this position.
expr = this.AddError(ParsePossibleRefExpression(), ErrorCode.ERR_InvalidExprTerm, SyntaxFacts.GetText(tk));
break;
default:
// check for intrinsic type followed by '.'
if (IsPredefinedType(tk))
Expand Down Expand Up @@ -10258,7 +10264,8 @@ private void ParseAnonymousTypeMemberInitializers(ref SyntaxToken openBrace, ref
list.Add(this.ParseAnonymousTypeMemberInitializer());

// additional arguments
while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseBraceToken)
{
Expand Down Expand Up @@ -10417,7 +10424,8 @@ private void ParseObjectOrCollectionInitializerMembers(ref SyntaxToken startToke
list.Add(this.ParseObjectOrCollectionInitializerMember(ref isObjectInitializer));

// additional arguments
while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseBraceToken)
{
Expand Down Expand Up @@ -10548,7 +10556,8 @@ private void ParseExpressionsForComplexElementInitializer(ref SyntaxToken openBr
list.Add(this.ParseExpressionCore());

// additional arguments
while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseBraceToken)
{
Expand Down Expand Up @@ -10644,7 +10653,8 @@ private InitializerExpressionSyntax ParseArrayInitializer()
{
list.Add(this.ParseVariableInitializer());

while (true)
int lastTokenPosition = -1;
while (IsMakingProgress(ref lastTokenPosition))
{
if (this.CurrentToken.Kind == SyntaxKind.CloseBraceToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1269,22 +1269,12 @@ void M()
}";

CreateCompilation(source2).VerifyDiagnostics(

// (9,16): error CS1525: Invalid expression term 'ref'
// o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(9, 16),
// (9,16): error CS1002: ; expected
// o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(9, 16),
// (9,20): error CS0118: 'o2' is a variable but is used like a type
// o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_BadSKknown, "o2").WithArguments("o2", "variable", "type").WithLocation(9, 20),
// (9,22): error CS1001: Identifier expected
// o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(9, 22),
// (9,22): error CS8174: A declaration of a by-reference variable must have an initializer
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref o2").WithArguments("ref").WithLocation(9, 16),
// (9,16): error CS1073: Unexpected token 'ref'
// o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(9, 22),
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 16),
// (10,13): error CS0118: 'o1' is a variable but is used like a type
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_BadSKknown, "o1").WithArguments("o1", "variable", "type").WithLocation(10, 13),
Expand All @@ -1302,20 +1292,10 @@ void M()
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(10, 16),
// (10,20): error CS1525: Invalid expression term 'ref'
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(10, 20),
// (10,20): error CS1002: ; expected
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref o2").WithArguments("ref").WithLocation(10, 20),
// (10,20): error CS1073: Unexpected token 'ref'
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(10, 20),
// (10,24): error CS0118: 'o2' is a variable but is used like a type
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_BadSKknown, "o2").WithArguments("o2", "variable", "type").WithLocation(10, 24),
// (10,26): error CS1001: Identifier expected
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(10, 26),
// (10,26): error CS8174: A declaration of a by-reference variable must have an initializer
// ref o1 ??= ref o2;
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(10, 26)
);
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(10, 20));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6023,25 +6023,31 @@ static bool M(TypedReference x, int* p, ref int z)
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(6, 23),
// (7,23): error CS1525: Invalid expression term 'ref'
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(7, 23),
// (7,23): error CS1002: ; expected
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref int").WithArguments("ref").WithLocation(7, 23),
// (7,27): error CS1525: Invalid expression term 'int'
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(7, 23),
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "int").WithArguments("int").WithLocation(7, 27),
// (7,31): error CS1002: ; expected
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_SemicolonExpected, "z0").WithLocation(7, 31),
// (6,28): error CS0103: The name 'p0' does not exist in the current context
// var p1 = p is int* p0; // syntax error 1
Diagnostic(ErrorCode.ERR_NameNotInContext, "p0").WithArguments("p0").WithLocation(6, 28),
// (7,31): error CS8174: A declaration of a by-reference variable must have an initializer
// (7,23): error CS1073: Unexpected token 'ref'
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 23),
// (7,31): error CS0103: The name 'z0' does not exist in the current context
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "z0").WithLocation(7, 31),
Diagnostic(ErrorCode.ERR_NameNotInContext, "z0").WithArguments("z0").WithLocation(7, 31),
// (7,31): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.ERR_IllegalStatement, "z0").WithLocation(7, 31),
// (9,23): error CS8121: An expression of type 'TypedReference' cannot be handled by a pattern of type 'object'.
// var b1 = x is object o1; // not allowed 1
Diagnostic(ErrorCode.ERR_PatternWrongType, "object").WithArguments("System.TypedReference", "object").WithLocation(9, 23),
// (10,23): error CS8521: Pattern-matching is not permitted for pointer types.
// var b2 = p is object o2; // not allowed 2
Diagnostic(ErrorCode.ERR_PointerTypeInPatternMatching, "object").WithLocation(10, 23),
// (7,31): warning CS0168: The variable 'z0' is declared but never used
// var r1 = z is ref int z0; // syntax error 2
Diagnostic(ErrorCode.WRN_UnreferencedVar, "z0").WithArguments("z0").WithLocation(7, 31)
Diagnostic(ErrorCode.ERR_PointerTypeInPatternMatching, "object").WithLocation(10, 23)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,69 +542,18 @@ ref int M(bool b, ref int x, ref int y)
}";
var compilation = CreateCompilationWithMscorlibAndSpan(source, options: TestOptions.DebugDll);
compilation.VerifyDiagnostics(
// (6,23): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive).
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithLocation(6, 23),
// (6,40): error CS1525: Invalid expression term 'ref'
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref").WithArguments("ref").WithLocation(6, 40),
// (6,40): error CS1003: Syntax error, ',' expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(6, 40),
// (6,40): error CS1513: } expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_RbraceExpected, "ref").WithLocation(6, 40),
// (6,40): error CS1026: ) expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_CloseParenExpected, "ref").WithLocation(6, 40),
// (6,40): error CS1002: ; expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ref").WithLocation(6, 40),
// (6,40): warning CS0162: Unreachable code detected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.WRN_UnreachableCode, "ref").WithLocation(6, 40),
// (6,44): error CS0118: 'x' is a variable but is used like a type
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_BadSKknown, "x").WithArguments("x", "variable", "type").WithLocation(6, 44),
// (6,45): error CS1001: Identifier expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_IdentifierExpected, ",").WithLocation(6, 45),
// (6,45): error CS8174: A declaration of a by-reference variable must have an initializer
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(6, 45),
// (6,47): error CS1001: Identifier expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_IdentifierExpected, "false").WithLocation(6, 47),
// (6,47): error CS1002: ; expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_SemicolonExpected, "false").WithLocation(6, 47),
// (6,47): error CS8174: A declaration of a by-reference variable must have an initializer
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(6, 47),
// (6,53): error CS1002: ; expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_SemicolonExpected, "=>").WithLocation(6, 53),
// (6,53): error CS1513: } expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_RbraceExpected, "=>").WithLocation(6, 53),
// (6,60): error CS0118: 'y' is a variable but is used like a type
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_BadSKknown, "y").WithArguments("y", "variable", "type").WithLocation(6, 60),
// (6,62): error CS1001: Identifier expected
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_IdentifierExpected, "}").WithLocation(6, 62),
// (6,62): error CS1002: ; expected
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref x").WithArguments("ref").WithLocation(6, 40),
// (6,40): error CS1073: Unexpected token 'ref'
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(6, 62),
// (6,62): error CS8174: A declaration of a by-reference variable must have an initializer
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 40),
// (6,56): error CS1525: Invalid expression term 'ref'
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_ByReferenceVariableMustBeInitialized, "").WithLocation(6, 62),
// (6,63): error CS1519: Invalid token ')' in class, struct, or interface member declaration
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref y").WithArguments("ref").WithLocation(6, 56),
// (6,56): error CS1073: Unexpected token 'ref'
// return ref (b switch { true => ref x, false => ref y });
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ")").WithArguments(")").WithLocation(6, 63),
// (8,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1));
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(6, 56));
}

[Fact]
Expand Down
Loading

0 comments on commit 02d1b3c

Please sign in to comment.