diff options
| author | bors <bors@rust-lang.org> | 2017-08-22 04:28:49 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2017-08-22 04:28:49 +0000 |
| commit | 6722996923157f2089cd5d7ead10f79162e0abb0 (patch) | |
| tree | 347c6a343b294adf6eaaad2e91eba995c5bf7059 /src/libsyntax | |
| parent | 942711e115834ea2b4d91e1b3d3ae84b69cad670 (diff) | |
| parent | f06323337dd0cf748e8a0ca49d91dac2eae6b4a9 (diff) | |
| download | rust-6722996923157f2089cd5d7ead10f79162e0abb0.tar.gz rust-6722996923157f2089cd5d7ead10f79162e0abb0.zip | |
Auto merge of #43854 - estebank:missing-cond, r=nikomatsakis
Point out missing if conditional
On a case where an else conditional is missing, point this out
instead of the token immediately after the (incorrect) else block:
```
error: missing condition for `if` statemementt push fork -f
--> $DIR/issue-13483.rs:16:5
|
13 | } else if {
| ^ expected if condition here
```
instead of
```
error: expected `{`, found `else`
--> ../../src/test/ui/issue-13483.rs:14:7
|
14 | } else {
| ^^^^
```
Fix #13483.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 26 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 12 |
2 files changed, 38 insertions, 0 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4e6641f4c50..fa4df2196a3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -844,6 +844,32 @@ pub struct Expr { pub attrs: ThinVec<Attribute> } +impl Expr { + /// Wether this expression would be valid somewhere that expects a value, for example, an `if` + /// condition. + pub fn returns(&self) -> bool { + if let ExprKind::Block(ref block) = self.node { + match block.stmts.last().map(|last_stmt| &last_stmt.node) { + // implicit return + Some(&StmtKind::Expr(_)) => true, + Some(&StmtKind::Semi(ref expr)) => { + if let ExprKind::Ret(_) = expr.node { + // last statement is explicit return + true + } else { + false + } + } + // This is a block that doesn't end in either an implicit or explicit return + _ => false, + } + } else { + // This is not a block, it is a value + true + } + } +} + impl fmt::Debug for Expr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "expr({}: {})", self.id, pprust::expr_to_string(self)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 84e3d8ddf70..2b2f925306d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2965,6 +2965,18 @@ impl<'a> Parser<'a> { } let lo = self.prev_span; let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?; + + // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then + // verify that the last statement is either an implicit return (no `;`) or an explicit + // return. This won't catch blocks with an explicit `return`, but that would be caught by + // the dead code lint. + if self.eat_keyword(keywords::Else) || !cond.returns() { + let sp = lo.next_point(); + let mut err = self.diagnostic() + .struct_span_err(sp, "missing condition for `if` statemement"); + err.span_label(sp, "expected if condition here"); + return Err(err) + } let thn = self.parse_block()?; let mut els: Option<P<Expr>> = None; let mut hi = thn.span; |
