use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
use rustc_session::lint::LintBuffer;
use rustc_session::Session;
-use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
use std::mem;
use syntax::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use syntax::walk_list;
+const MORE_EXTERN: &str =
+ "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html";
+
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
enum SelfSemantic {
Yes,
}
}
- fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
- if asyncness.is_async() {
- struct_span_err!(self.session, span, E0706, "trait fns cannot be declared `async`")
- .note("`async` trait functions are not currently supported")
- .note(
- "consider using the `async-trait` crate: \
- https://crates.io/crates/async-trait",
- )
- .emit();
+ fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
+ if let Async::Yes { span, .. } = asyncness {
+ struct_span_err!(
+ self.session,
+ fn_span,
+ E0706,
+ "functions in traits cannot be declared `async`"
+ )
+ .span_label(span, "`async` because of this")
+ .note("`async` trait functions are not currently supported")
+ .note("consider using the `async-trait` crate: https://crates.io/crates/async-trait")
+ .emit();
}
}
- fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
- if constness.node == Constness::Const {
+ fn check_trait_fn_not_const(&self, constness: Const) {
+ if let Const::Yes(span) = constness {
struct_span_err!(
self.session,
- constness.span,
+ span,
E0379,
- "trait fns cannot be declared const"
+ "functions in traits cannot be declared const"
)
- .span_label(constness.span, "trait fns cannot be const")
+ .span_label(span, "functions in traits cannot be const")
.emit();
}
}
}
}
- fn check_impl_assoc_type_no_bounds(&self, bounds: &[GenericBound]) {
+ fn check_type_no_bounds(&self, bounds: &[GenericBound], ctx: &str) {
let span = match bounds {
[] => return,
[b0] => b0.span(),
[b0, .., bl] => b0.span().to(bl.span()),
};
self.err_handler()
- .struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
+ .struct_span_err(span, &format!("bounds on `type`s in {} have no effect", ctx))
+ .emit();
+ }
+
+ fn check_foreign_ty_genericless(&self, generics: &Generics) {
+ let cannot_have = |span, descr, remove_descr| {
+ self.err_handler()
+ .struct_span_err(
+ span,
+ &format!("`type`s inside `extern` blocks cannot have {}", descr),
+ )
+ .span_suggestion(
+ span,
+ &format!("remove the {}", remove_descr),
+ String::new(),
+ Applicability::MaybeIncorrect,
+ )
+ .span_label(self.current_extern_span(), "`extern` block begins here")
+ .note(MORE_EXTERN)
+ .emit();
+ };
+
+ if !generics.params.is_empty() {
+ cannot_have(generics.span, "generic parameters", "generic parameters");
+ }
+
+ if !generics.where_clause.predicates.is_empty() {
+ cannot_have(generics.where_clause.span, "`where` clauses", "`where` clause");
+ }
+ }
+
+ fn check_foreign_kind_bodyless(&self, ident: Ident, kind: &str, body: Option<Span>) {
+ let body = match body {
+ None => return,
+ Some(body) => body,
+ };
+ self.err_handler()
+ .struct_span_err(ident.span, &format!("incorrect `{}` inside `extern` block", kind))
+ .span_label(ident.span, "cannot have a body")
+ .span_label(body, "the invalid body")
+ .span_label(
+ self.current_extern_span(),
+ format!(
+ "`extern` blocks define existing foreign {0}s and {0}s \
+ inside of them cannot have a body",
+ kind
+ ),
+ )
+ .note(MORE_EXTERN)
.emit();
}
"`extern` blocks define existing foreign functions and functions \
inside of them cannot have a body",
)
- .note("for more information, visit https://doc.rust-lang.org/std/keyword.extern.html")
+ .note(MORE_EXTERN)
.emit();
}
}
}
+ fn error_foreign_const(&self, ident: Ident, span: Span) {
+ self.err_handler()
+ .struct_span_err(ident.span, "extern items cannot be `const`")
+ .span_suggestion(
+ span.with_hi(ident.span.lo()),
+ "try using a static value",
+ "static ".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .span_label(self.current_extern_span(), "in this `extern` block")
+ .note(MORE_EXTERN)
+ .emit();
+ }
+
/// Reject C-varadic type unless the function is foreign,
/// or free and `unsafe extern "C"` semantically.
fn check_c_varadic_type(&self, fk: FnKind<'a>) {
(Some(FnCtxt::Foreign), _) => return,
(Some(FnCtxt::Free), Some(header)) => match header.ext {
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
- if header.unsafety == Unsafety::Unsafe =>
+ if matches!(header.unsafety, Unsafe::Yes(_)) =>
{
return;
}
/// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
/// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
- if sig.header.constness.node == Constness::Const {
+ if let Const::Yes(const_span) = sig.header.constness {
// Look for const generics and error if we find any.
for param in &generics.params {
if let GenericParamKind::Const { .. } = param.kind {
self.err_handler()
- .struct_span_err(span, "const parameters are not permitted in `const fn`")
+ .struct_span_err(
+ span,
+ "const parameters are not permitted in const functions",
+ )
+ .span_label(const_span, "`const` because of this")
.emit();
}
}
}
}
+
+ fn check_item_named(&self, ident: Ident, kind: &str) {
+ if ident.name != kw::Underscore {
+ return;
+ }
+ self.err_handler()
+ .struct_span_err(ident.span, &format!("`{}` items in this context need a name", kind))
+ .span_label(ident.span, format!("`_` is not a valid name for this `{}` item", kind))
+ .emit();
+ }
}
enum GenericPosition {
.help("use `auto trait Trait {}` instead")
.emit();
}
- if unsafety == Unsafety::Unsafe && polarity == ImplPolarity::Negative {
+ if let (Unsafe::Yes(span), ImplPolarity::Negative) = (unsafety, polarity) {
struct_span_err!(
this.session,
item.span,
E0198,
"negative impls cannot be unsafe"
)
+ .span_label(span, "unsafe because of this")
.emit();
}
&item.vis,
Some("place qualifiers on individual impl items instead"),
);
- if unsafety == Unsafety::Unsafe {
+ if let Unsafe::Yes(span) = unsafety {
struct_span_err!(
self.session,
item.span,
E0197,
"inherent impls cannot be unsafe"
)
+ .span_label(span, "unsafe because of this")
.emit();
}
if polarity == ImplPolarity::Negative {
.note("only trait implementations may be annotated with default")
.emit();
}
- if constness == Constness::Const {
+ if let Const::Yes(span) = constness {
self.err_handler()
.struct_span_err(item.span, "inherent impls cannot be `const`")
+ .span_label(span, "`const` because of this")
.note("only trait implementations may be annotated with `const`")
.emit();
}
self.err_handler().span_err(item.span, "unions cannot have zero fields");
}
}
+ ItemKind::Const(.., None) => {
+ let msg = "free constant item without body";
+ self.error_item_without_body(item.span, "constant", msg, " = <expr>;");
+ }
+ ItemKind::Static(.., None) => {
+ let msg = "free static item without body";
+ self.error_item_without_body(item.span, "static", msg, " = <expr>;");
+ }
_ => {}
}
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
}
- ForeignItemKind::Static(..) | ForeignItemKind::Ty | ForeignItemKind::Macro(..) => {}
+ ForeignItemKind::TyAlias(generics, bounds, body) => {
+ self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+ self.check_type_no_bounds(bounds, "`extern` blocks");
+ self.check_foreign_ty_genericless(generics);
+ }
+ ForeignItemKind::Static(_, _, body) => {
+ self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
+ }
+ ForeignItemKind::Const(..) => {
+ self.error_foreign_const(fi.ident, fi.span);
+ }
+ ForeignItemKind::Macro(..) => {}
}
visit::walk_foreign_item(self, fi)
)
.span_label(predicate.span, "not supported")
.note(
- "for more information, see https://github.com/rust-lang/rust/issues/20041",
+ "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
+ for more information",
)
.emit();
}
self.check_c_varadic_type(fk);
+ // Functions cannot both be `const async`
+ if let Some(FnHeader {
+ constness: Const::Yes(cspan),
+ asyncness: Async::Yes { span: aspan, .. },
+ ..
+ }) = fk.header()
+ {
+ self.err_handler()
+ .struct_span_err(span, "functions cannot be both `const` and `async`")
+ .span_label(*cspan, "`const` because of this")
+ .span_label(*aspan, "`async` because of this")
+ .emit();
+ }
+
// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
AssocItemKind::Const(_, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
- AssocItemKind::Fn(_, body) => {
+ AssocItemKind::Fn(_, _, body) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(bounds, body) => {
+ AssocItemKind::TyAlias(_, bounds, body) => {
self.check_impl_item_provided(item.span, body, "type", " = <type>;");
- self.check_impl_assoc_type_no_bounds(bounds);
+ self.check_type_no_bounds(bounds, "`impl`s");
}
_ => {}
}
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
- if let AssocItemKind::Fn(sig, _) = &item.kind {
+ if let AssocItemKind::Fn(sig, _, _) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
- self.check_trait_fn_not_async(item.span, sig.header.asyncness.node);
+ self.check_trait_fn_not_async(item.span, sig.header.asyncness);
}
}
+ match item.kind {
+ AssocItemKind::Const(..) => self.check_item_named(item.ident, "const"),
+ AssocItemKind::Static(..) => self
+ .err_handler()
+ .struct_span_err(item.span, "associated `static` items are not allowed")
+ .emit(),
+ _ => {}
+ }
+
self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
}
}