Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}

fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) -> bool {
if attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) {
if attr.has_any_name(&[sym::cfg_trace, sym::cfg_attr_trace, sym::test_trace]) {
// It's not a valid identifier, so avoid printing it
// to keep the printed code reasonably parse-able.
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
sym::cfg_attr_trace,
// testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
sym::test,
sym::test_trace,
sym::ignore,
sym::should_panic,
sym::bench,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub(crate) mod rustc_internal;
pub(crate) mod semantics;
pub(crate) mod stability;
pub(crate) mod test_attrs;
pub(crate) mod trace;
pub(crate) mod traits;
pub(crate) mod transparency;
pub(crate) mod util;
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/trace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use super::prelude::*;

pub(crate) struct TestTraceParser;

impl<S: Stage> NoArgsAttributeParser<S> for TestTraceParser {
const PATH: &[Symbol] = &[sym::test_trace];

const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;

const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);

const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::TestTrace;
}
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ use crate::attributes::stability::{
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
};
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
use crate::attributes::trace::TestTraceParser;
use crate::attributes::traits::{
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
Expand Down Expand Up @@ -291,6 +292,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<TestTraceParser>>,
Single<WithoutArgs<ThreadLocalParser>>,
Single<WithoutArgs<TrackCallerParser>>,
Single<WithoutArgs<TypeConstParser>>,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/validate_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use rustc_span::{Span, Symbol, sym};
use crate::{AttributeParser, Late, session_diagnostics as errors};

pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
if attr.is_doc_comment()
|| attr.has_any_name(&[sym::cfg_trace, sym::cfg_attr_trace, sym::test_trace])
{
return;
}
Expand Down
11 changes: 10 additions & 1 deletion compiler/rustc_builtin_macros/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, Diag, Level};
use rustc_expand::base::*;
use rustc_expand::config::attr_into_trace;
use rustc_hir::Attribute;
use rustc_hir::attrs::AttributeKind;
use rustc_span::{ErrorGuaranteed, Ident, RemapPathScopeComponents, Span, Symbol, sym};
Expand Down Expand Up @@ -113,7 +114,7 @@ pub(crate) fn expand_test_or_bench(
item: Annotatable,
is_bench: bool,
) -> Vec<Annotatable> {
let (item, is_stmt) = match item {
let (mut item, is_stmt) = match item {
Annotatable::Item(i) => (i, false),
Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true),
other => {
Expand All @@ -136,6 +137,14 @@ pub(crate) fn expand_test_or_bench(
return vec![];
}

// Add a trace to the originating test function, so that we can
// check if attributes that have `#[test]` or `#[bench]` as a requirement
// actually are annotated with said attributes
item.attrs.push(attr_into_trace(
cx.attr_word(sym::test_trace, cx.with_def_site_ctxt(attr_sp)),
sym::test_trace,
));

if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) {
cx.dcx().emit_err(errors::NakedFunctionTestingAttribute {
testing_span: attr_sp,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec
.collect()
}

pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute {
pub fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute {
match &mut attr.kind {
AttrKind::Normal(normal) => {
let NormalAttr { item, tokens } = &mut **normal;
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
EncodeCrossCrate::No
),
ungated!(
test_trace, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No
),

// ==========================================================================
// Internal attributes, Diagnostics related:
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,9 @@ pub enum AttributeKind {
/// `#[unsafe(force_target_feature(enable = "...")]`.
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },

/// Represents `#[<test_trace>]`
TestTrace,

/// Represents `#[thread_local]`
ThreadLocal,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ impl AttributeKind {
Stability { .. } => Yes,
StdInternalSymbol(..) => No,
TargetFeature { .. } => No,
TestTrace => No,
ThreadLocal => No,
TrackCaller(..) => Yes,
TypeConst(..) => Yes,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ passes_attr_application_struct_union =
attribute should be applied to a struct or union
.label = not a struct or union

passes_attr_must_be_applied_to_test_or_bench = `#[{$attr_name}]` should only be applied to functions annotated with `#[test]` or `#[bench]`

passes_autodiff_attr =
`#[autodiff]` should be applied to a function
.label = not a function
Expand Down
31 changes: 29 additions & 2 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id,target)
},
Attribute::Parsed(AttributeKind::DoNotRecommend{attr_span}) => {self.check_do_not_recommend(*attr_span, hir_id, target, item)},
Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => {
self.check_should_panic(attrs, *span, target);
},
Attribute::Parsed(AttributeKind::Ignore { span, .. }) => {
self.check_ignore(attrs, *span, target);
}
Attribute::Parsed(
AttributeKind::EiiDeclaration { .. }
| AttributeKind::EiiForeignItem
Expand All @@ -235,7 +241,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::Pointee(..)
| AttributeKind::Dummy
| AttributeKind::RustcBuiltinMacro { .. }
| AttributeKind::Ignore { .. }
| AttributeKind::InstructionSet(..)
| AttributeKind::Path(..)
| AttributeKind::NoImplicitPrelude(..)
Expand Down Expand Up @@ -286,7 +291,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::PassByValue (..)
| AttributeKind::StdInternalSymbol (..)
| AttributeKind::Coverage (..)
| AttributeKind::ShouldPanic { .. }
| AttributeKind::Coroutine(..)
| AttributeKind::Linkage(..)
| AttributeKind::MustUse { .. }
Expand Down Expand Up @@ -316,6 +320,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcDumpDefParents
| AttributeKind::RustcDumpVtable(..)
| AttributeKind::NeedsAllocator
| AttributeKind::TestTrace
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
Expand Down Expand Up @@ -484,6 +489,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_mix_no_mangle_export(hir_id, attrs);
}

fn check_ignore(&self, attrs: &[Attribute], attr_span: Span, target: Target) {
// The error message only makes sense if it's actually being applied on a function
if matches!(target, Target::Fn) {
if !find_attr!(attrs, AttributeKind::TestTrace) {
self.dcx()
.emit_err(errors::MustBeAppliedToTest { attr_span, attr_name: sym::ignore });
}
}
}

fn check_should_panic(&self, attrs: &[Attribute], attr_span: Span, target: Target) {
// The error message only makes sense if it's actually being applied on a function
if matches!(target, Target::Fn) {
if !find_attr!(attrs, AttributeKind::TestTrace) {
self.dcx().emit_err(errors::MustBeAppliedToTest {
attr_span,
attr_name: sym::should_panic,
});
}
}
}

fn check_rustc_must_implement_one_of(
&self,
attr_span: Span,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,3 +1316,11 @@ pub(crate) struct FunctionNamesDuplicated {
#[primary_span]
pub spans: Vec<Span>,
}

#[derive(Diagnostic)]
#[diag(passes_attr_must_be_applied_to_test_or_bench)]
pub(crate) struct MustBeAppliedToTest {
#[primary_span]
pub attr_span: Span,
pub attr_name: Symbol,
}
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,7 @@ symbols! {
test_case,
test_removed_feature,
test_runner,
test_trace: "<test_trace>",
test_unstable_lint,
thread,
thread_local,
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/attributes/ignore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(test)]

#[ignore]
//~^ ERROR `#[ignore]` should only be applied to functions annotated with `#[test]` or `#[bench]`
pub fn foo() {}


#[test]
#[ignore]
pub fn bar() {}

#[ignore]
#[bench]
pub fn bazz() {}

fn main() { }
8 changes: 8 additions & 0 deletions tests/ui/attributes/ignore.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: `#[ignore]` should only be applied to functions annotated with `#[test]` or `#[bench]`
--> $DIR/ignore.rs:3:1
|
LL | #[ignore]
| ^^^^^^^^^

error: aborting due to 1 previous error

16 changes: 16 additions & 0 deletions tests/ui/attributes/should-panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(test)]

#[should_panic]
//~^ ERROR `#[should_panic]` should only be applied to functions annotated with `#[test]` or `#[bench]`
pub fn foo() {}


#[test]
#[should_panic]
pub fn bar() {}

#[should_panic]
#[bench]
pub fn bazz() {}

fn main() { }
8 changes: 8 additions & 0 deletions tests/ui/attributes/should-panic.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: `#[should_panic]` should only be applied to functions annotated with `#[test]` or `#[bench]`
--> $DIR/should-panic.rs:3:1
|
LL | #[should_panic]
| ^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

20 changes: 20 additions & 0 deletions tests/ui/attributes/test_trace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//@ compile-flags: --test

fn main() {}

#[test_trace]
//~^ ERROR cannot find attribute `test_trace` in this scope
fn foo() {}


#[test]
#[test_trace]
//~^ ERROR cannot find attribute `test_trace` in this scope
fn bar() {}

#[test]
#[test_trace]
//~^ ERROR cannot find attribute `test_trace` in this scope
#[test]
//~^ WARN duplicated attribute
fn bazz() {}
46 changes: 46 additions & 0 deletions tests/ui/attributes/test_trace.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
error: cannot find attribute `test_trace` in this scope
--> $DIR/test_trace.rs:5:3
|
LL | #[test_trace]
| ^^^^^^^^^^
|
help: a built-in attribute with a similar name exists
|
LL - #[test_trace]
LL + #[<test_trace>]
|

error: cannot find attribute `test_trace` in this scope
--> $DIR/test_trace.rs:11:3
|
LL | #[test_trace]
| ^^^^^^^^^^
|
help: a built-in attribute with a similar name exists
|
LL - #[test_trace]
LL + #[<test_trace>]
|

error: cannot find attribute `test_trace` in this scope
--> $DIR/test_trace.rs:16:3
|
LL | #[test_trace]
| ^^^^^^^^^^
|
help: a built-in attribute with a similar name exists
|
LL - #[test_trace]
LL + #[<test_trace>]
|

warning: duplicated attribute
--> $DIR/test_trace.rs:18:1
|
LL | #[test]
| ^^^^^^^
|
= note: `#[warn(duplicate_macro_attributes)]` on by default

error: aborting due to 3 previous errors; 1 warning emitted

8 changes: 6 additions & 2 deletions tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ fn b() {}
#[unsafe(test)] //~ ERROR: is not an unsafe attribute
fn aa() {}

#[unsafe(ignore = "test")] //~ ERROR: is not an unsafe attribute
#[unsafe(ignore = "test")]
//~^ ERROR: is not an unsafe attribute
//~| ERROR `#[ignore]` should only be applied to functions annotated with `#[test]` or `#[bench]`
fn bb() {}

#[unsafe(should_panic(expected = "test"))] //~ ERROR: is not an unsafe attribute
#[unsafe(should_panic(expected = "test"))]
//~^ ERROR: is not an unsafe attribute
//~| ERROR `#[should_panic]` should only be applied to functions annotated with `#[test]` or `#[bench]`
fn cc() {}

#[unsafe(macro_use)] //~ ERROR: is not an unsafe attribute
Expand Down
Loading
Loading