Skip to content

Commit e1fd8aa

Browse files
authored
[Parse] Fix crash in conditional compilation parsing (#7331)
1 parent 1e7a572 commit e1fd8aa

File tree

8 files changed

+34
-32
lines changed

8 files changed

+34
-32
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,14 @@ ERROR(extra_rbrace,none,
5555
ERROR(structure_overflow,Fatal,
5656
"structure nesting level exceeded maximum of %0", (unsigned))
5757

58+
ERROR(expected_close_to_if_directive,none,
59+
"expected #else or #endif at end of conditional compilation block", ())
60+
ERROR(expected_close_after_else_directive,none,
61+
"further conditions after #else are unreachable", ())
5862
ERROR(unexpected_conditional_compilation_block_terminator,none,
5963
"unexpected conditional compilation block terminator", ())
60-
ERROR(expected_conditional_compilation_expression,none,
61-
"expected a condition to follow %select{#if|#elseif}0", (bool))
64+
ERROR(incomplete_conditional_compilation_directive,none,
65+
"incomplete condition in conditional compilation directive", ())
6266
ERROR(extra_tokens_conditional_compilation_directive,none,
6367
"extra tokens following conditional compilation directive", ())
6468

@@ -828,12 +832,6 @@ ERROR(expected_expr_assignment,none,
828832
ERROR(expected_rbrace_in_brace_stmt,none,
829833
"expected '}' at end of brace statement", ())
830834

831-
/// #if Statement
832-
ERROR(expected_close_to_if_directive,none,
833-
"expected #else or #endif at end of conditional compilation block", ())
834-
ERROR(expected_close_after_else_directive,none,
835-
"further conditions after #else are unreachable", ())
836-
837835
/// Associatedtype Statement
838836
ERROR(typealias_inside_protocol_without_type,none,
839837
"typealias is missing an assigned type; use 'associatedtype' to define an associated type requirement", ())

lib/Parse/ParseDecl.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,11 +3015,6 @@ ParserResult<IfConfigDecl> Parser::parseDeclIfConfig(ParseDeclOptions Flags) {
30153015
if (isElse) {
30163016
ConfigState.setConditionActive(!foundActive);
30173017
} else {
3018-
if (Tok.isAtStartOfLine()) {
3019-
diagnose(ClauseLoc, diag::expected_conditional_compilation_expression,
3020-
!Clauses.empty());
3021-
}
3022-
30233018
// Evaluate the condition.
30243019
ParserResult<Expr> Result = parseExprSequence(diag::expected_expr,
30253020
/*isBasic*/true,

lib/Parse/ParseExpr.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
180180
}
181181
}
182182
SequencedExprs.push_back(Primary.get());
183+
184+
if (isForConditionalDirective && Tok.isAtStartOfLine())
185+
break;
183186

184187
parse_operator:
185188
switch (Tok.getKind()) {
@@ -320,17 +323,17 @@ ParserResult<Expr> Parser::parseExprSequence(Diag<> Message,
320323
}
321324
}
322325
done:
323-
324-
if (SequencedExprs.empty()) {
325-
if (isForConditionalDirective) {
326-
diagnose(startLoc, diag::expected_close_to_if_directive);
327-
return makeParserError();
328-
} else {
329-
// If we had semantic errors, just fail here.
330-
assert(!SequencedExprs.empty());
331-
}
326+
327+
// For conditional directives, we stop parsing after a line break.
328+
if (isForConditionalDirective && (SequencedExprs.size() & 1) == 0) {
329+
diagnose(getEndOfPreviousLoc(),
330+
diag::incomplete_conditional_compilation_directive);
331+
return makeParserError();
332332
}
333333

334+
// If we had semantic errors, just fail here.
335+
assert(!SequencedExprs.empty());
336+
334337
// If we saw no operators, don't build a sequence.
335338
if (SequencedExprs.size() == 1) {
336339
auto Result = makeParserResult(SequencedExprs[0]);

lib/Parse/ParseStmt.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,11 +1784,6 @@ ParserResult<Stmt> Parser::parseStmtIfConfig(BraceItemListKind Kind) {
17841784
if (isElse) {
17851785
ConfigState.setConditionActive(!foundActive);
17861786
} else {
1787-
if (Tok.isAtStartOfLine()) {
1788-
diagnose(ClauseLoc, diag::expected_conditional_compilation_expression,
1789-
!Clauses.empty());
1790-
}
1791-
17921787
// Evaluate the condition.
17931788
ParserResult<Expr> Result = parseExprSequence(diag::expected_expr,
17941789
/*basic*/true,

test/Parse/ConditionalCompilation/basicParseErrors.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ func h() {}
3232

3333
#endif
3434

35+
36+
// <https://twitter.com/practicalswift/status/829066902869786625>
37+
#if // expected-error {{incomplete condition in conditional compilation directive}}
38+
#if 0 == // expected-error {{incomplete condition in conditional compilation directive}}
39+
#if0= // expected-error {{incomplete condition in conditional compilation directive}} expected-error {{'=' must have consistent whitespace on both sides}}
40+
class Foo {
41+
#if // expected-error {{incomplete condition in conditional compilation directive}}
42+
#if 0 == // expected-error {{incomplete condition in conditional compilation directive}}
43+
#if0= // expected-error {{incomplete condition in conditional compilation directive}} expected-error {{'=' must have consistent whitespace on both sides}}
44+
}
45+
3546
struct S {
3647
#if FOO
3748
#else

test/Parse/ConditionalCompilation/no_configuration_error1.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
// With a space next to the '#if'
44
#if
5-
// expected-error@-1 {{expected a condition to follow #if}}
6-
class C {} //expected-error {{expected #else or #endif at end of conditional compilation block}}
5+
// expected-error@-1 {{incomplete condition in conditional compilation directive}}
6+
class C {}
77
#endif // expected-error {{unexpected conditional compilation block terminator}}

test/Parse/ConditionalCompilation/no_configuration_error2.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// No space next to the '#if'
44

55
#if
6-
// expected-error@-1 {{expected a condition to follow #if}}
7-
class D {} // expected-error {{expected #else or #endif at end of conditional compilation block}}
6+
// expected-error@-1 {{incomplete condition in conditional compilation directive}}
7+
class D {}
88
#endif
99
// expected-error@-1 {{unexpected conditional compilation block terminator}}

validation-test/compiler_crashers/28610-elements-size-1-even-number-of-elements-in-sequence.swift renamed to validation-test/compiler_crashers_fixed/28610-elements-size-1-even-number-of-elements-in-sequence.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
// RUN: not %target-swift-frontend %s -emit-ir
99
// REQUIRES: asserts
1010
#if0 *

0 commit comments

Comments
 (0)