about summary refs log tree commit diff
path: root/src/libsyntax/parse/diagnostics.rs
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2019-07-13 21:15:21 -0700
committerEsteban Küber <esteban@kuber.com.ar>2019-07-13 22:24:11 -0700
commitc8d9cd99fa2f389a69c0c42de9945f46977b11d7 (patch)
treea70feac92e2938627d6300829c670c9b38b8c22c /src/libsyntax/parse/diagnostics.rs
parent69656fa4cbafc378fd63f9186d93b0df3cdd9320 (diff)
downloadrust-c8d9cd99fa2f389a69c0c42de9945f46977b11d7.tar.gz
rust-c8d9cd99fa2f389a69c0c42de9945f46977b11d7.zip
Detect `fn` with a body in an `extern` block
Diffstat (limited to 'src/libsyntax/parse/diagnostics.rs')
-rw-r--r--src/libsyntax/parse/diagnostics.rs37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs
index ae24047ac82..de392d6bb81 100644
--- a/src/libsyntax/parse/diagnostics.rs
+++ b/src/libsyntax/parse/diagnostics.rs
@@ -15,6 +15,7 @@ use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
 use rustc_data_structures::fx::FxHashSet;
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 use log::{debug, trace};
+use std::mem;
 
 /// Creates a placeholder argument.
 crate fn dummy_arg(ident: Ident) -> Arg {
@@ -783,6 +784,42 @@ impl<'a> Parser<'a> {
         Err(err)
     }
 
+    crate fn parse_semi_or_incorrect_foreign_fn_body(
+        &mut self,
+        ident: &Ident,
+        extern_sp: Span,
+    ) -> PResult<'a, ()> {
+        if self.token != token::Semi {
+            // this might be an incorrect fn definition (#62109)
+            let parser_snapshot = self.clone();
+            match self.parse_inner_attrs_and_block() {
+                Ok((_, body)) => {
+                    self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block")
+                        .span_label(ident.span, "can't have a body")
+                        .span_label(body.span, "this body is invalid here")
+                        .span_label(
+                            extern_sp,
+                            "`extern` blocks define existing foreign functions and `fn`s \
+                             inside of them can't have a body")
+                        .help("you might have meant to write a function accessible through ffi, \
+                               which can be done by writing `extern fn` outside of the \
+                               `extern` block")
+                        .note("for more information, visit \
+                               https://doc.rust-lang.org/std/keyword.extern.html")
+                        .emit();
+                }
+                Err(mut err) => {
+                    err.cancel();
+                    mem::replace(self, parser_snapshot);
+                    self.expect(&token::Semi)?;
+                }
+            }
+        } else {
+            self.bump();
+        }
+        Ok(())
+    }
+
     /// Consume alternative await syntaxes like `await <expr>`, `await? <expr>`, `await(<expr>)`
     /// and `await { <expr> }`.
     crate fn parse_incorrect_await_syntax(