Skip to content

Commit c0ebfe9

Browse files
committed
On outer attr not found, avoid knock-down errors
When we encounter code like ```rust struct S; fn main() { S.clone(); } ``` we avoid emitting errors about the `derive` (which isn't early resolved as normal, but *has* a later resolution) and stop the compiler from advancing to later stages, to avoid knock down errors from the `derive` not being evaluated. Recovering these would be possible, but would produce incorrect errors in the cases where had the outer attribute been present it would have modified the behavior/evaluation of the `derive` attributes. Fix rust-lang#118455.
1 parent 0e2dac8 commit c0ebfe9

File tree

7 files changed

+72
-34
lines changed

7 files changed

+72
-34
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
10391039
if let Ok((Some(ext), _)) = this.resolve_macro_path(
10401040
derive,
10411041
Some(MacroKind::Derive),
1042+
ast::AttrStyle::Outer,
10421043
parent_scope,
10431044
false,
10441045
false,

compiler/rustc_resolve/src/ident.rs

+1
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
443443
match this.resolve_macro_path(
444444
derive,
445445
Some(MacroKind::Derive),
446+
ast::AttrStyle::Outer,
446447
parent_scope,
447448
true,
448449
force,

compiler/rustc_resolve/src/late.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3868,9 +3868,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
38683868
if qself.is_none() {
38693869
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
38703870
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
3871-
if let Ok((_, res)) =
3872-
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
3873-
{
3871+
if let Ok((_, res)) = self.r.resolve_macro_path(
3872+
&path,
3873+
None,
3874+
AttrStyle::Outer,
3875+
&self.parent_scope,
3876+
false,
3877+
false,
3878+
) {
38743879
return Ok(Some(PartialRes::new(res)));
38753880
}
38763881
}

compiler/rustc_resolve/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ pub struct Resolver<'a, 'tcx> {
10461046
proc_macro_stubs: FxHashSet<LocalDefId>,
10471047
/// Traces collected during macro resolution and validated when it's complete.
10481048
single_segment_macro_resolutions:
1049-
Vec<(Ident, MacroKind, ParentScope<'a>, Option<NameBinding<'a>>)>,
1049+
Vec<(Ident, MacroKind, ast::AttrStyle, ParentScope<'a>, Option<NameBinding<'a>>)>,
10501050
multi_segment_macro_resolutions:
10511051
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'a>, Option<Res>)>,
10521052
builtin_attrs: Vec<(Ident, ParentScope<'a>)>,

compiler/rustc_resolve/src/macros.rs

+56-19
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_ast_pretty::pprust;
1515
use rustc_attr::StabilityLevel;
1616
use rustc_data_structures::intern::Interned;
1717
use rustc_data_structures::sync::Lrc;
18-
use rustc_errors::{struct_span_err, Applicability};
18+
use rustc_errors::{struct_span_err, Applicability, FatalError};
1919
use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
2020
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
2121
use rustc_expand::compile_declarative_macro;
@@ -268,15 +268,19 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
268268
}
269269
};
270270

271-
let (path, kind, inner_attr, derives) = match invoc.kind {
271+
let (path, kind, attr_kind, derives) = match invoc.kind {
272272
InvocationKind::Attr { ref attr, ref derives, .. } => (
273273
&attr.get_normal_item().path,
274274
MacroKind::Attr,
275-
attr.style == ast::AttrStyle::Inner,
275+
attr.style,
276276
self.arenas.alloc_ast_paths(derives),
277277
),
278-
InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
279-
InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
278+
InvocationKind::Bang { ref mac, .. } => {
279+
(&mac.path, MacroKind::Bang, ast::AttrStyle::Outer, &[][..])
280+
}
281+
InvocationKind::Derive { ref path, .. } => {
282+
(path, MacroKind::Derive, ast::AttrStyle::Outer, &[][..])
283+
}
280284
};
281285

282286
// Derives are not included when `invocations` are collected, so we have to add them here.
@@ -287,7 +291,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
287291
path,
288292
kind,
289293
supports_macro_expansion,
290-
inner_attr,
294+
attr_kind,
291295
parent_scope,
292296
node_id,
293297
force,
@@ -373,6 +377,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
373377
match self.resolve_macro_path(
374378
path,
375379
Some(MacroKind::Derive),
380+
ast::AttrStyle::Outer,
376381
&parent_scope,
377382
true,
378383
force,
@@ -498,19 +503,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
498503
path: &ast::Path,
499504
kind: MacroKind,
500505
supports_macro_expansion: SupportsMacroExpansion,
501-
inner_attr: bool,
506+
attr_kind: ast::AttrStyle,
502507
parent_scope: &ParentScope<'a>,
503508
node_id: NodeId,
504509
force: bool,
505510
soft_custom_inner_attributes_gate: bool,
506511
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
507-
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
508-
{
509-
Ok((Some(ext), res)) => (ext, res),
510-
Ok((None, res)) => (self.dummy_ext(kind), res),
511-
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
512-
Err(Determinacy::Undetermined) => return Err(Indeterminate),
513-
};
512+
let (ext, res) =
513+
match self.resolve_macro_path(path, Some(kind), attr_kind, parent_scope, true, force) {
514+
Ok((Some(ext), res)) => (ext, res),
515+
Ok((None, res)) => (self.dummy_ext(kind), res),
516+
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
517+
Err(Determinacy::Undetermined) => return Err(Indeterminate),
518+
};
514519

515520
// Report errors for the resolved macro.
516521
for segment in &path.segments {
@@ -549,7 +554,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
549554
match supports_macro_expansion {
550555
SupportsMacroExpansion::No => Some(("a", "non-macro attribute")),
551556
SupportsMacroExpansion::Yes { supports_inner_attrs } => {
552-
if inner_attr && !supports_inner_attrs {
557+
if let ast::AttrStyle::Inner = attr_kind
558+
&& !supports_inner_attrs
559+
{
553560
Some(("a", "non-macro inner attribute"))
554561
} else {
555562
None
@@ -588,7 +595,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
588595
}
589596

590597
// We are trying to avoid reporting this error if other related errors were reported.
591-
if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
598+
if res != Res::Err
599+
&& let ast::AttrStyle::Inner = attr_kind
600+
&& !self.tcx.features().custom_inner_attributes
601+
{
592602
let msg = match res {
593603
Res::Def(..) => "inner macro attributes are unstable",
594604
Res::NonMacroAttr(..) => "custom inner attributes are unstable",
@@ -627,6 +637,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
627637
&mut self,
628638
path: &ast::Path,
629639
kind: Option<MacroKind>,
640+
attr_kind: ast::AttrStyle,
630641
parent_scope: &ParentScope<'a>,
631642
trace: bool,
632643
force: bool,
@@ -685,6 +696,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
685696
self.single_segment_macro_resolutions.push((
686697
path[0].ident,
687698
kind,
699+
attr_kind,
688700
*parent_scope,
689701
binding.ok(),
690702
));
@@ -794,7 +806,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
794806
}
795807

796808
let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions);
797-
for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
809+
let mut has_reported_inner_attr_error = false;
810+
let mut raise_fatal_error = false;
811+
for (ident, kind, attr_kind, parent_scope, initial_binding) in macro_resolutions {
798812
match self.early_resolve_ident_in_lexical_scope(
799813
ident,
800814
ScopeSet::Macro(kind),
@@ -810,7 +824,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
810824
});
811825
let res = binding.res();
812826
let seg = Segment::from_ident(ident);
813-
check_consistency(self, &[seg], ident.span, kind, initial_res, res);
827+
if has_reported_inner_attr_error
828+
&& let Res::Def(DefKind::Macro(MacroKind::Attr), _) = res
829+
&& let None = initial_res
830+
{
831+
// Do not emit an indeterminate resolution and later errors when an outer
832+
// attribute wasn't found, as this can be knock down effects. #118455
833+
raise_fatal_error = true;
834+
} else {
835+
let res = binding.res();
836+
check_consistency(self, &[seg], ident.span, kind, initial_res, res);
837+
};
814838
if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
815839
let node_id = self
816840
.invocation_parents
@@ -825,7 +849,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
825849
);
826850
}
827851
}
828-
Err(..) => {
852+
Err(_) => {
853+
if let ast::AttrStyle::Inner = attr_kind {
854+
has_reported_inner_attr_error = true;
855+
}
829856
let expected = kind.descr_expected();
830857

831858
let mut err = self.tcx.sess.create_err(CannotFindIdentInThisScope {
@@ -851,6 +878,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
851878
None,
852879
);
853880
}
881+
882+
if raise_fatal_error {
883+
// When we encounter an inner attribute failure, and subsequent successful macro
884+
// resolutions following early resolution failures. This is so when an outer attribute
885+
// isn't found, and we encounter `derive` attributes, we won't raise errors caused by
886+
// any code that relies on those derives having been evaluated. We don't attempt to
887+
// recover because the behavior of those derives could have been modified by the outer
888+
// attribute, causing *other* errors, so it is safest to just stop early instead.
889+
FatalError.raise();
890+
}
854891
}
855892

856893
fn check_stability_and_deprecation(

tests/ui/proc-macro/derive-helper-legacy-spurious.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
#[macro_use]
66
extern crate test_macros;
77

8-
#[derive(Empty)] //~ ERROR cannot determine resolution for the attribute macro `derive`
8+
#[derive(Empty, Clone)] // no error emitted here
99
#[empty_helper] //~ ERROR cannot find attribute `empty_helper` in this scope
1010
struct Foo {}
1111

12-
fn main() {}
12+
fn main() {
13+
let _ = Foo.clone(); // no error emitted here
14+
}

tests/ui/proc-macro/derive-helper-legacy-spurious.stderr

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,11 @@ error: cannot find attribute `dummy` in this scope
44
LL | #![dummy]
55
| ^^^^^
66

7-
error: cannot determine resolution for the attribute macro `derive`
8-
--> $DIR/derive-helper-legacy-spurious.rs:8:3
9-
|
10-
LL | #[derive(Empty)]
11-
| ^^^^^^
12-
|
13-
= note: import resolution is stuck, try simplifying macro imports
14-
157
error: cannot find attribute `empty_helper` in this scope
168
--> $DIR/derive-helper-legacy-spurious.rs:9:3
179
|
1810
LL | #[empty_helper]
1911
| ^^^^^^^^^^^^
2012

21-
error: aborting due to 3 previous errors
13+
error: aborting due to 2 previous errors
2214

0 commit comments

Comments
 (0)