diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c74ae2343b8..2662e709991 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2058,6 +2058,33 @@ fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> + 'x ``` "##, +E0910: r##" +This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed +on something other than a struct or enum. + +Examples of erroneous code: + +```compile_fail,E0910 +# #![feature(non_exhaustive)] + +#[non_exhaustive] +trait Foo { } +``` +"##, + +E0911: r##" +This error indicates that a `#[non_exhaustive]` attribute had a value. The +`#[non_exhaustive]` should be empty. + +Examples of erroneous code: + +```compile_fail,E0911 +# #![feature(non_exhaustive)] + +#[non_exhaustive(anything)] +struct Foo; +``` +"##, } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 316ed07ca05..956cd17f38f 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -66,6 +66,8 @@ fn check_attributes(&self, item: &hir::Item, target: Target) { for attr in &item.attrs { if attr.check_name("inline") { self.check_inline(attr, &item.span, target) + } else if attr.check_name("non_exhaustive") { + self.check_non_exhaustive(attr, item, target) } else if attr.check_name("wasm_import_module") { has_wasm_import_module = true; if attr.value_str().is_none() { @@ -113,6 +115,31 @@ fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { } } + /// Check if the `#[non_exhaustive]` attribute on an `item` is valid. + fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { + match target { + Target::Struct | Target::Enum => { /* Valid */ }, + _ => { + struct_span_err!(self.tcx.sess, + attr.span, + E0910, + "attribute can only be applied to a struct or enum") + .span_label(item.span, "not a struct or enum") + .emit(); + return; + } + } + + if attr.meta_item_list().is_some() || attr.value_str().is_some() { + struct_span_err!(self.tcx.sess, + attr.span, + E0911, + "attribute should be empty") + .span_label(item.span, "not empty") + .emit(); + } + } + /// Check if the `#[repr]` attributes on `item` are valid. fn check_repr(&self, item: &hir::Item, target: Target) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: diff --git a/src/test/compile-fail/rfc-2008-non-exhaustive/invalid-attribute.rs b/src/test/compile-fail/rfc-2008-non-exhaustive/invalid-attribute.rs new file mode 100644 index 00000000000..e48d989c01d --- /dev/null +++ b/src/test/compile-fail/rfc-2008-non-exhaustive/invalid-attribute.rs @@ -0,0 +1,28 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(non_exhaustive)] + +#[non_exhaustive(anything)] +//~^ ERROR attribute should be empty [E0911] +struct Foo; + +#[non_exhaustive] +//~^ ERROR attribute can only be applied to a struct or enum [E0910] +trait Bar { } + +#[non_exhaustive] +//~^ ERROR attribute can only be applied to a struct or enum [E0910] +union Baz { + f1: u16, + f2: u16 +} + +fn main() { }