Skip to content

Commit

Permalink
Supress unhelpful diagnostics for unresolved top level attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Jan 27, 2024
1 parent 04521fd commit 5c89b70
Show file tree
Hide file tree
Showing 35 changed files with 189 additions and 282 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_attr/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ attr_incorrect_repr_format_generic =
attr_incorrect_repr_format_packed_one_or_zero_arg =
incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
attr_invalid_attr_at_crate_level =
`{$name}` attribute cannot be used at crate level
.suggestion = perhaps you meant to use an outer attribute
attr_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind}
attr_invalid_issue_string =
`issue` must be a non-zero numeric string or "none"
.must_not_be_zero = `issue` must not be "0", use "none" instead
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ pub use StabilityLevel::*;
pub use rustc_ast::attr::*;

pub(crate) use rustc_session::HashStableContext;
pub use session_diagnostics::{InvalidAttrAtCrateLevel, ItemFollowingInnerAttr};

rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
37 changes: 37 additions & 0 deletions compiler/rustc_attr/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,40 @@ pub(crate) struct UnknownVersionLiteral {
#[primary_span]
pub span: Span,
}

pub struct InvalidAttrAtCrateLevel {
pub span: Span,
pub sugg_span: Option<Span>,
pub name: Symbol,
pub item: Option<ItemFollowingInnerAttr>,
}

#[derive(Clone, Copy)]
pub struct ItemFollowingInnerAttr {
pub span: Span,
pub kind: &'static str,
}

impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel {
#[track_caller]
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag = DiagnosticBuilder::new(dcx, level, fluent::attr_invalid_attr_at_crate_level);
diag.set_span(self.span);
diag.set_arg("name", self.name);
// Only emit an error with a suggestion if we can create a string out
// of the attribute span
if let Some(span) = self.sugg_span {
diag.span_suggestion_verbose(
span,
fluent::attr_suggestion,
String::new(),
Applicability::MachineApplicable,
);
}
if let Some(item) = self.item {
diag.set_arg("kind", item.kind);
diag.span_label(item.span, fluent::attr_invalid_attr_at_crate_level_item);
}
diag
}
}
7 changes: 0 additions & 7 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -389,13 +389,6 @@ passes_inline_not_fn_or_closure =
passes_inner_crate_level_attr =
crate-level attribute should be in the root module
passes_invalid_attr_at_crate_level =
`{$name}` attribute cannot be used at crate level
.suggestion = perhaps you meant to use an outer attribute
passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind}
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
Expand Down
15 changes: 3 additions & 12 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2503,12 +2503,8 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
}
}

// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
// from this check.
// Built-in macros will be checked in resolve.
fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
// Check for builtin attributes at the crate level
// which were unsuccessfully resolved due to cannot determine
// resolution for the attribute macro error.
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::repr,
Expand All @@ -2517,11 +2513,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
sym::start,
sym::rustc_main,
sym::unix_sigpipe,
sym::derive,
sym::test,
sym::test_case,
sym::global_allocator,
sym::bench,
];

for attr in attrs {
Expand All @@ -2535,11 +2526,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
.items()
.map(|id| tcx.hir().item(id))
.find(|item| !item.span.is_dummy()) // Skip prelude `use`s
.map(|item| errors::ItemFollowingInnerAttr {
.map(|item| rustc_attr::ItemFollowingInnerAttr {
span: item.ident.span,
kind: item.kind.descr(),
});
tcx.dcx().emit_err(errors::InvalidAttrAtCrateLevel {
tcx.dcx().emit_err(rustc_attr::InvalidAttrAtCrateLevel {
span: attr.span,
sugg_span: tcx
.sess
Expand Down
38 changes: 0 additions & 38 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,44 +856,6 @@ pub struct UnknownLangItem {
pub name: Symbol,
}

pub struct InvalidAttrAtCrateLevel {
pub span: Span,
pub sugg_span: Option<Span>,
pub name: Symbol,
pub item: Option<ItemFollowingInnerAttr>,
}

#[derive(Clone, Copy)]
pub struct ItemFollowingInnerAttr {
pub span: Span,
pub kind: &'static str,
}

impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for InvalidAttrAtCrateLevel {
#[track_caller]
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let mut diag =
DiagnosticBuilder::new(dcx, level, fluent::passes_invalid_attr_at_crate_level);
diag.span(self.span);
diag.arg("name", self.name);
// Only emit an error with a suggestion if we can create a string out
// of the attribute span
if let Some(span) = self.sugg_span {
diag.span_suggestion_verbose(
span,
fluent::passes_suggestion,
String::new(),
Applicability::MachineApplicable,
);
}
if let Some(item) = self.item {
diag.arg("kind", item.kind);
diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item);
}
diag
}
}

#[derive(Diagnostic)]
#[diag(passes_duplicate_diagnostic_item_in_crate)]
pub struct DuplicateDiagnosticItemInCrate {
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable {
pub(crate) span: Span,
pub(crate) target: Ident,
}

#[derive(Subdiagnostic)]
#[suggestion(
resolve_suggestion,
code = "",
applicability = "machine-applicable",
style = "verbose"
)]
pub(crate) struct InvalidAttrSugg {
#[primary_span]
pub(crate) span: Span,
pub(crate) name: Symbol,
}
58 changes: 50 additions & 8 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use crate::{BuiltinMacroState, Determinacy, MacroData};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
use rustc_ast::{self as ast, attr, Crate, Inline, ItemKind, ModKind, NodeId};
use rustc_ast::{
self as ast, attr, AttrStyle, Attribute, Crate, Inline, ItemKind, ModKind, NodeId,
};
use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel;
use rustc_data_structures::intern::Interned;
Expand All @@ -35,7 +37,7 @@ use rustc_span::edition::Edition;
use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
use rustc_span::hygiene::{AstPass, MacroKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{BytePos, Span, DUMMY_SP};
use std::cell::Cell;
use std::mem;

Expand Down Expand Up @@ -689,6 +691,32 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res))
}

fn report_invalid_crate_level_attr(&mut self, attrs: &[Attribute], name: Symbol) -> bool {
for attr in attrs.iter().filter(|attr| attr.style == AttrStyle::Inner) {
if attr.has_name(name) {
let tcx = self.tcx;
tcx.dcx().emit_err(rustc_attr::InvalidAttrAtCrateLevel {
span: attr.span,
sugg_span: tcx
.sess
.source_map()
.span_to_snippet(attr.span)
.ok()
.filter(|src| src.starts_with("#!["))
.map(|_| {
attr.span
.with_lo(attr.span.lo() + BytePos(1))
.with_hi(attr.span.lo() + BytePos(2))
}),
name,
item: None,
});
return true;
}
}
false
}

pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) {
let check_consistency = |this: &mut Self,
path: &[Segment],
Expand All @@ -708,15 +736,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// expanded into a dummy fragment for recovery during expansion.
// Now, post-expansion, the resolution may succeed, but we can't change the
// past and need to report an error.
// However, non-speculative `resolve_path` can successfully return private items
// Special cases:
// 1. non-speculative `resolve_path` can successfully return private items
// even if speculative `resolve_path` returned nothing previously, so we skip this
// less informative error if the privacy error is reported elsewhere.
// 2. issue #118455, unresolved top level attribute error didn't imported prelude and
// already have emitted an error, report builtin macro and attributes error by the way,
// so `check_invalid_crate_level_attr` in can ignore them.

if this.privacy_errors.is_empty() {
this.dcx().emit_err(CannotDetermineMacroResolution {
span,
kind: kind.descr(),
path: Segment::names_to_string(path),
});
if this.is_builtin_macro(res)
|| this.builtin_attrs_bindings.values().any(|b| b.res() == res)
{
if !this.report_invalid_crate_level_attr(&krate.attrs, path[0].ident.name) {
return;
}
if this.tcx.dcx().has_errors().is_none() {
this.dcx().emit_err(CannotDetermineMacroResolution {
span,
kind: kind.descr(),
path: Segment::names_to_string(path),
});
}
}
}
}
};
Expand Down
10 changes: 5 additions & 5 deletions tests/ui/derives/issue-36617.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#![derive(Copy)] //~ ERROR cannot determine resolution for the attribute macro `derive`
#![derive(Copy)]
//~^ ERROR `derive` attribute cannot be used at crate level

#![test]//~ ERROR cannot determine resolution for the attribute macro `test`
#![test]
//~^ ERROR `test` attribute cannot be used at crate level

#![test_case]//~ ERROR cannot determine resolution for the attribute macro `test_case`
#![test_case]
//~^ ERROR `test_case` attribute cannot be used at crate level

#![bench]//~ ERROR cannot determine resolution for the attribute macro `bench`
#![bench]
//~^ ERROR `bench` attribute cannot be used at crate level

#![global_allocator]//~ ERROR cannot determine resolution for the attribute macro `global_allocator`
#![global_allocator]
//~^ ERROR `global_allocator` attribute cannot be used at crate level

fn main() {}
57 changes: 1 addition & 56 deletions tests/ui/derives/issue-36617.stderr
Original file line number Diff line number Diff line change
@@ -1,51 +1,8 @@
error: cannot determine resolution for the attribute macro `derive`
--> $DIR/issue-36617.rs:1:4
|
LL | #![derive(Copy)]
| ^^^^^^
|
= note: import resolution is stuck, try simplifying macro imports

error: cannot determine resolution for the attribute macro `test`
--> $DIR/issue-36617.rs:4:4
|
LL | #![test]
| ^^^^
|
= note: import resolution is stuck, try simplifying macro imports

error: cannot determine resolution for the attribute macro `test_case`
--> $DIR/issue-36617.rs:7:4
|
LL | #![test_case]
| ^^^^^^^^^
|
= note: import resolution is stuck, try simplifying macro imports

error: cannot determine resolution for the attribute macro `bench`
--> $DIR/issue-36617.rs:10:4
|
LL | #![bench]
| ^^^^^
|
= note: import resolution is stuck, try simplifying macro imports

error: cannot determine resolution for the attribute macro `global_allocator`
--> $DIR/issue-36617.rs:13:4
|
LL | #![global_allocator]
| ^^^^^^^^^^^^^^^^
|
= note: import resolution is stuck, try simplifying macro imports

error: `derive` attribute cannot be used at crate level
--> $DIR/issue-36617.rs:1:1
|
LL | #![derive(Copy)]
| ^^^^^^^^^^^^^^^^
...
LL | fn main() {}
| ---- the inner attribute doesn't annotate this function
|
help: perhaps you meant to use an outer attribute
|
Expand All @@ -58,9 +15,6 @@ error: `test` attribute cannot be used at crate level
|
LL | #![test]
| ^^^^^^^^
...
LL | fn main() {}
| ---- the inner attribute doesn't annotate this function
|
help: perhaps you meant to use an outer attribute
|
Expand All @@ -73,9 +27,6 @@ error: `test_case` attribute cannot be used at crate level
|
LL | #![test_case]
| ^^^^^^^^^^^^^
...
LL | fn main() {}
| ---- the inner attribute doesn't annotate this function
|
help: perhaps you meant to use an outer attribute
|
Expand All @@ -88,9 +39,6 @@ error: `bench` attribute cannot be used at crate level
|
LL | #![bench]
| ^^^^^^^^^
...
LL | fn main() {}
| ---- the inner attribute doesn't annotate this function
|
help: perhaps you meant to use an outer attribute
|
Expand All @@ -103,15 +51,12 @@ error: `global_allocator` attribute cannot be used at crate level
|
LL | #![global_allocator]
| ^^^^^^^^^^^^^^^^^^^^
...
LL | fn main() {}
| ---- the inner attribute doesn't annotate this function
|
help: perhaps you meant to use an outer attribute
|
LL - #![global_allocator]
LL + #[global_allocator]
|

error: aborting due to 10 previous errors
error: aborting due to 5 previous errors

1 change: 0 additions & 1 deletion tests/ui/extenv/issue-55897.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ mod unresolved_env {
use env; //~ ERROR unresolved import `env`

include!(concat!(env!("NON_EXISTENT"), "/data.rs"));
//~^ ERROR cannot determine resolution for the macro `env`
}

mod nonexistent_env {
Expand Down
Loading

0 comments on commit 5c89b70

Please sign in to comment.