From 3980342f3164a62ba7036711c16cc8af20d06418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 3 Dec 2019 22:19:18 -0800 Subject: [PATCH 01/14] Use structured suggestion for disambiguating method calls Fix #65635. --- src/librustc/ty/mod.rs | 11 ++ src/librustc_typeck/check/expr.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 127 +++++++++++++----- .../associated-const-ambiguity-report.stderr | 10 +- src/test/ui/error-codes/E0034.stderr | 10 +- .../inference_unstable_featured.stderr | 10 +- src/test/ui/issues/issue-18446.stderr | 6 +- src/test/ui/issues/issue-3702-2.stderr | 10 +- .../issue-65634-raw-ident-suggestion.stderr | 10 +- ...method-ambig-two-traits-cross-crate.stderr | 10 +- ...method-ambig-two-traits-from-bounds.stderr | 10 +- .../method-ambig-two-traits-from-impls.stderr | 10 +- ...method-ambig-two-traits-from-impls2.stderr | 10 +- ...mbig-two-traits-with-default-method.stderr | 10 +- ...e-trait-object-with-separate-params.stderr | 15 ++- src/test/ui/span/issue-37767.stderr | 30 ++++- src/test/ui/span/issue-7575.stderr | 20 ++- .../ui/traits/trait-alias-ambiguous.stderr | 10 +- 18 files changed, 248 insertions(+), 74 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78a31f4e54466..15bbfa7860fa7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -212,6 +212,17 @@ pub enum AssocKind { Type } +impl AssocKind { + pub fn suggestion_descr(&self) -> &'static str { + match self { + ty::AssocKind::Method => "method call", + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => "associated type", + ty::AssocKind::Const => "associated constant", + } + } +} + impl AssocItem { pub fn def_kind(&self) -> DefKind { match self.kind { diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5bfc60c754067..b11a8a7ab5336 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1422,8 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: ast::Ident, ) -> Ty<'tcx> { let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(base.span, - expr_t); + let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f4b53b4d10604..cd26e6f237c7d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -82,34 +82,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let print_disambiguation_help = | err: &mut DiagnosticBuilder<'_>, trait_name: String, + rcvr_ty: Ty<'_>, + kind: ty::AssocKind, + span: Span, + candidate: Option, | { - err.help(&format!( - "to disambiguate the method call, write `{}::{}({}{})` instead", - trait_name, - item_name, - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_ptr() { - "&mut " + let mut applicability = Applicability::MachineApplicable; + let sugg_args = if let ty::AssocKind::Method = kind { + format!( + "({}{})", + if rcvr_ty.is_region_ptr() && args.is_some() { + if rcvr_ty.is_mutable_ptr() { + "&mut " + } else { + "&" + } } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg - .iter() - .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) - .unwrap_or_else(|_| "...".to_owned())) - .collect::>() - .join(", ") - ).unwrap_or_else(|| "...".to_owned()) - )); + "" + }, + args.map(|arg| arg + .iter() + .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "...".to_owned() + })) + .collect::>() + .join(", ") + ).unwrap_or_else(|| { + applicability = Applicability::HasPlaceholders; + "...".to_owned() + }), + ) + } else { + String::new() + }; + let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); + err.span_suggestion( + span, + &format!( + "disambiguate the {} for {}", + kind.suggestion_descr(), + if let Some(candidate) = candidate { + format!("candidate #{}", candidate) + } else { + "the candidate".to_string() + }, + ), + sugg, + applicability, + ); }; let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, mut sources: Vec, + sugg_span: Span, | { sources.sort(); sources.dedup(); @@ -150,15 +179,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let note_str = if sources.len() > 1 { - format!("candidate #{} is defined in an impl{} for the type `{}`", - idx + 1, - insertion, - impl_ty) + let (note_str, idx) = if sources.len() > 1 { + (format!( + "candidate #{} is defined in an impl{} for the type `{}`", + idx + 1, + insertion, + impl_ty, + ), Some(idx + 1)) } else { - format!("the candidate is defined in an impl{} for the type `{}`", - insertion, - impl_ty) + (format!( + "the candidate is defined in an impl{} for the type `{}`", + insertion, + impl_ty, + ), None) }; if let Some(note_span) = note_span { // We have a span pointing to the method. Show note with snippet. @@ -168,7 +201,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(¬e_str); } if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { - print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id)); + let path = self.tcx.def_path_str(trait_ref.def_id); + + let ty = match item.kind { + ty::AssocKind::Const | + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => rcvr_ty, + ty::AssocKind::Method => self.tcx.fn_sig(item.def_id) + .inputs() + .skip_binder() + .get(0) + .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .map(|ty| *ty) + .unwrap_or(rcvr_ty), + }; + print_disambiguation_help(err, path, ty, item.kind, sugg_span, idx); } } CandidateSource::TraitSource(trait_did) => { @@ -182,19 +229,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let item_span = self.tcx.sess.source_map() .def_span(self.tcx.def_span(item.def_id)); - if sources.len() > 1 { + let idx = if sources.len() > 1 { span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", idx + 1, self.tcx.def_path_str(trait_did)); + Some(idx + 1) } else { span_note!(err, item_span, "the candidate is defined in the trait `{}`", self.tcx.def_path_str(trait_did)); - } - print_disambiguation_help(err, self.tcx.def_path_str(trait_did)); + None + }; + let path = self.tcx.def_path_str(trait_did); + print_disambiguation_help(err, path, rcvr_ty, item.kind, sugg_span, idx); } } } @@ -203,6 +253,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + let sugg_span = if let SelfSource::MethodCall(expr) = source { + // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. + self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span + } else { + span + }; + match error { MethodError::NoMatch(NoMatchData { static_candidates: static_sources, @@ -495,9 +552,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } else if static_sources.len() > 1 { - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } if !unsatisfied_predicates.is_empty() { @@ -584,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "multiple applicable items in scope"); err.span_label(span, format!("multiple `{}` found", item_name)); - report_candidates(span, &mut err, sources); + report_candidates(span, &mut err, sources, sugg_span); err.emit(); } diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr index bb217bd182db6..92a8d19021a2c 100644 --- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` | LL | const ID: i32 = 1; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::ID(...)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::ID(...)` instead +help: disambiguate the associated constant for candidate #1 + | +LL | const X: i32 = Foo::ID; + | ^^^^^^^ +help: disambiguate the associated constant for candidate #2 + | +LL | const X: i32 = Bar::ID; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index a58d16bfafb59..30b44fd402bb8 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait1::foo(...)` instead note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test` --> $DIR/E0034.rs:16:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait2::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | Trait1::foo(...)() + | ^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Trait2::foo(...)() + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index b06a6298a571c..fa908440e41ea 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -5,9 +5,15 @@ LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead +help: disambiguate the method call for candidate #1 + | +LL | assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr index e6afc4c13a912..3422add9dd96b 100644 --- a/src/test/ui/issues/issue-18446.stderr +++ b/src/test/ui/issues/issue-18446.stderr @@ -2,7 +2,10 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-18446.rs:18:7 | LL | x.foo(); - | ^^^ multiple `foo` found + | --^^^-- + | | | + | | multiple `foo` found + | help: disambiguate the method call for candidate #2: `T::foo(&x)` | note: candidate #1 is defined in an impl for the type `dyn T` --> $DIR/issue-18446.rs:9:5 @@ -14,7 +17,6 @@ note: candidate #2 is defined in the trait `T` | LL | fn foo(&self); | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `T::foo(&x)` instead error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr index 4d0ff750c254c..b18e407c3d464 100644 --- a/src/test/ui/issues/issue-3702-2.stderr +++ b/src/test/ui/issues/issue-3702-2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type | LL | fn to_int(&self) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead note: candidate #2 is defined in an impl of the trait `Add` for the type `isize` --> $DIR/issue-3702-2.rs:14:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Add::to_int(&self)` instead +help: disambiguate the method call for candidate #1 + | +LL | ToPrimitive::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Add::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr index c7bb653dc1f14..feaf3dc753ffb 100644 --- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead +help: disambiguate the method call for candidate #1 + | +LL | async::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | await::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 9f46a722a508e..fa3add81a28f5 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,9 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Me2::me(1_usize)` instead = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` - = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | fn main() { Me2::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr index 6c493c67e29d9..b6c81c2377ee4 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | trait A { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(t)` instead note: candidate #2 is defined in the trait `B` --> $DIR/method-ambig-two-traits-from-bounds.rs:2:11 | LL | trait B { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(t); + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(t); + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr index 0b3724e030fa4..71c65f7ccc68d 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(AB {})` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls.rs:11:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(AB {})` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(AB {}); + | ^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(AB {}); + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 81c99b33c813e..55499215799d7 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(...)` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(...)(); + | ^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(...)(); + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr index dc8aef2503739..3dbb17371004a 100644 --- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` | LL | trait Foo { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::method(1_usize)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 | LL | trait Bar { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::method(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | Foo::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Bar::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index c9d7da84e09f4..e7f295df8c482 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -25,19 +25,28 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `internal::X::foo(x)` instead note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead note: candidate #3 is defined in the trait `FinalFoo` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `FinalFoo::foo(x)` instead +help: disambiguate the method call for candidate #1 + | +LL | let z = internal::X::foo(x); + | ^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | let z = nuisance_foo::NuisanceFoo::foo(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | let z = FinalFoo::foo(x); + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr index 0bbff45436c23..9ed6c8b826f79 100644 --- a/src/test/ui/span/issue-37767.stderr +++ b/src/test/ui/span/issue-37767.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(&a)` instead note: candidate #2 is defined in the trait `B` --> $DIR/issue-37767.rs:6:5 | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:22:7 @@ -28,13 +34,19 @@ note: candidate #1 is defined in the trait `C` | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `C::foo(&a)` instead note: candidate #2 is defined in the trait `D` --> $DIR/issue-37767.rs:18:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `D::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | C::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | D::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:34:7 @@ -47,13 +59,19 @@ note: candidate #1 is defined in the trait `E` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `E::foo(a)` instead note: candidate #2 is defined in the trait `F` --> $DIR/issue-37767.rs:30:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `F::foo(a)` instead +help: disambiguate the method call for candidate #1 + | +LL | E::foo(a) + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | F::foo(a) + | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 36db5bea86294..53a6238422b57 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -10,24 +10,33 @@ note: candidate #1 is defined in the trait `CtxtFn` | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead note: candidate #2 is defined in the trait `OtherTrait` --> $DIR/issue-7575.rs:8:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead note: candidate #3 is defined in the trait `UnusedTrait` --> $DIR/issue-7575.rs:17:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `f9`, perhaps you need to implement one of them: candidate #1: `CtxtFn` candidate #2: `OtherTrait` candidate #3: `UnusedTrait` +help: disambiguate the method call for candidate #1 + | +LL | u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `fff` found for type `Myisize` in the current scope --> $DIR/issue-7575.rs:62:30 @@ -60,8 +69,11 @@ note: the candidate is defined in the trait `ManyImplTrait` | LL | fn is_str() -> bool { | ^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead = help: items from traits can only be used if the type parameter is bounded by the trait +help: disambiguate the method call for the candidate + | +LL | ManyImplTrait::is_str(t) + | help: the following trait defines an item `is_str`, perhaps you need to restrict type parameter `T` with it: | LL | fn param_bound(t: T) -> bool { diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index cde7dd0824924..48a029104aeca 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::A::foo(t)` instead note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | inner::A::foo(&t); + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | inner::B::foo(&t); + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error From 8c4f1d5f875e29e9a6e063744b71dc0a3c7deb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 11 Dec 2019 18:20:29 -0800 Subject: [PATCH 02/14] review comments --- src/librustc_typeck/check/method/suggest.rs | 134 ++++++++++-------- src/test/ui/error-codes/E0034.stderr | 8 +- ...method-ambig-two-traits-from-impls2.stderr | 8 +- 3 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index cd26e6f237c7d..9cd8c9abfd783 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,7 +15,7 @@ use rustc::traits::Obligation; use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; -use syntax::ast; +use syntax::{ast, source_map}; use syntax::util::lev_distance; use rustc_error_codes::*; @@ -79,61 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let print_disambiguation_help = | - err: &mut DiagnosticBuilder<'_>, - trait_name: String, - rcvr_ty: Ty<'_>, - kind: ty::AssocKind, - span: Span, - candidate: Option, - | { - let mut applicability = Applicability::MachineApplicable; - let sugg_args = if let ty::AssocKind::Method = kind { - format!( - "({}{})", - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_ptr() { - "&mut " - } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg - .iter() - .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) - .unwrap_or_else(|_| { - applicability = Applicability::HasPlaceholders; - "...".to_owned() - })) - .collect::>() - .join(", ") - ).unwrap_or_else(|| { - applicability = Applicability::HasPlaceholders; - "...".to_owned() - }), - ) - } else { - String::new() - }; - let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); - err.span_suggestion( - span, - &format!( - "disambiguate the {} for {}", - kind.suggestion_descr(), - if let Some(candidate) = candidate { - format!("candidate #{}", candidate) - } else { - "the candidate".to_string() - }, - ), - sugg, - applicability, - ); - }; - let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, @@ -215,7 +160,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|ty| *ty) .unwrap_or(rcvr_ty), }; - print_disambiguation_help(err, path, ty, item.kind, sugg_span, idx); + print_disambiguation_help( + item_name, + args, + err, + path, + ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } CandidateSource::TraitSource(trait_did) => { @@ -244,7 +199,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None }; let path = self.tcx.def_path_str(trait_did); - print_disambiguation_help(err, path, rcvr_ty, item.kind, sugg_span, idx); + print_disambiguation_help( + item_name, + args, + err, + path, + rcvr_ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } } @@ -1180,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { hir::intravisit::NestedVisitorMap::None } } + +fn print_disambiguation_help( + item_name: ast::Ident, + args: Option<&'tcx [hir::Expr]>, + err: &mut DiagnosticBuilder<'_>, + trait_name: String, + rcvr_ty: Ty<'_>, + kind: ty::AssocKind, + span: Span, + candidate: Option, + source_map: &source_map::SourceMap, +) { + let mut applicability = Applicability::MachineApplicable; + let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) { + format!( + "({}{})", + if rcvr_ty.is_region_ptr() { + if rcvr_ty.is_mutable_ptr() { + "&mut " + } else { + "&" + } + } else { + "" + }, + args.iter() + .map(|arg| source_map.span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::>() + .join(", "), + ) + } else { + String::new() + }; + let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); + err.span_suggestion( + span, + &format!( + "disambiguate the {} for {}", + kind.suggestion_descr(), + if let Some(candidate) = candidate { + format!("candidate #{}", candidate) + } else { + "the candidate".to_string() + }, + ), + sugg, + applicability, + ); +} diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 30b44fd402bb8..6db2ef5051d83 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the method call for candidate #1 | -LL | Trait1::foo(...)() - | ^^^^^^^^^^^^^^^^ +LL | Trait1::foo() + | ^^^^^^^^^^^ help: disambiguate the method call for candidate #2 | -LL | Trait2::foo(...)() - | ^^^^^^^^^^^^^^^^ +LL | Trait2::foo() + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 55499215799d7..44f85071505d2 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -16,12 +16,12 @@ LL | fn foo() {} | ^^^^^^^^ help: disambiguate the method call for candidate #1 | -LL | A::foo(...)(); - | ^^^^^^^^^^^ +LL | A::foo(); + | ^^^^^^ help: disambiguate the method call for candidate #2 | -LL | B::foo(...)(); - | ^^^^^^^^^^^ +LL | B::foo(); + | ^^^^^^ error: aborting due to previous error From 8a4632dec69082301d3fe67e48d422bc9fb665be Mon Sep 17 00:00:00 2001 From: Ohad Ravid Date: Fri, 13 Dec 2019 19:54:18 +0100 Subject: [PATCH 03/14] Indicate origin of where type parameter for uninferred types --- .../infer/error_reporting/need_type_info.rs | 78 +++++++++++++++---- src/librustc/infer/mod.rs | 5 +- src/librustc/infer/resolve.rs | 2 +- src/librustc/infer/type_variable.rs | 3 +- src/librustc/traits/error_reporting.rs | 2 +- .../async-await/unresolved_type_param.stderr | 2 +- .../fn-const-param-infer.stderr | 2 +- src/test/ui/consts/issue-64662.stderr | 4 +- src/test/ui/error-codes/E0401.stderr | 2 +- src/test/ui/issues/issue-12028.stderr | 2 +- src/test/ui/issues/issue-16966.stderr | 2 +- src/test/ui/issues/issue-17551.stderr | 2 +- src/test/ui/issues/issue-25368.stderr | 2 +- src/test/ui/issues/issue-5062.stderr | 2 +- src/test/ui/issues/issue-6458-2.stderr | 2 +- src/test/ui/issues/issue-6458-3.stderr | 2 +- src/test/ui/issues/issue-6458.stderr | 2 +- .../missing-type-parameter.stderr | 2 +- .../span/type-annotations-needed-expr.stderr | 2 +- ...ts-multidispatch-convert-ambig-dest.stderr | 2 +- .../or_else-multiple-type-params.stderr | 2 +- src/test/ui/type-inference/sort_by_key.stderr | 2 +- .../unbounded-associated-type.stderr | 2 +- ...ed-type-param-in-fn-with-assoc-type.stderr | 2 +- .../unbounded-type-param-in-fn.stderr | 2 +- .../ui/type/type-annotation-needed.stderr | 2 +- src/test/ui/unconstrained-none.stderr | 2 +- src/test/ui/unconstrained-ref.stderr | 2 +- 28 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 8878683f3a7a4..ebb94cc72ffe0 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -3,7 +3,7 @@ use crate::hir::{self, Body, FunctionRetTy, Expr, ExprKind, HirId, Local, Pat}; use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use crate::infer::InferCtxt; use crate::infer::type_variable::TypeVariableOriginKind; -use crate::ty::{self, Ty, Infer, TyVar}; +use crate::ty::{self, Ty, Infer, TyVar, DefIdTree}; use crate::ty::print::Print; use syntax::source_map::DesugaringKind; use syntax::symbol::kw; @@ -117,6 +117,8 @@ fn closure_return_type_suggestion( descr: &str, name: &str, ret: &str, + parent_name: Option, + parent_descr: Option<&str>, ) { let (arrow, post) = match output { FunctionRetTy::DefaultReturn(_) => ("-> ", " "), @@ -138,7 +140,12 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); + err.span_label(span, InferCtxt::missing_type_msg( + &name, + &descr, + parent_name, + parent_descr + )); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -177,16 +184,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, ty: Ty<'tcx>, highlight: Option, - ) -> (String, Option, Cow<'static, str>) { + ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { let ty_vars = self.type_variables.borrow(); let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { + let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); + let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { + let parent_name = self.tcx.def_key(parent_def_id).disambiguated_data.data + .get_opt_name().map(|parent_symbol| parent_symbol.to_string()); + + let type_parent_desc = self.tcx.def_kind(parent_def_id) + .map(|parent_def_kind| parent_def_kind.descr(parent_def_id)); + + (parent_name, type_parent_desc) + } else { + (None, None) + }; + if name != kw::SelfUpper { return ( name.to_string(), Some(var_origin.span), "type parameter".into(), + parent_name, + parent_desc, ); } } @@ -198,7 +220,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { printer.region_highlight_mode = highlight; } let _ = ty.print(printer); - (s, None, ty.prefix_string()) + (s, None, ty.prefix_string(), None, None) } pub fn need_type_info_err( @@ -209,7 +231,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr) = self.extract_type_name(&ty, None); + let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); let ty_to_string = |ty: Ty<'tcx>| -> String { @@ -218,7 +241,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_vars = self.type_variables.borrow(); let getter = move |ty_vid| { let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name) = var_origin.kind { + if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { return Some(name.to_string()); } None @@ -317,6 +340,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &descr, &name, &ret, + parent_name, + parent_descr, ); // We don't want to give the other suggestions when the problem is the // closure return type. @@ -433,8 +458,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if !err.span.span_labels().iter().any(|span_label| { span_label.label.is_some() && span_label.span == span }) && local_visitor.found_arg_pattern.is_none() - { // Avoid multiple labels pointing at `span`. - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); + { + // Avoid multiple labels pointing at `span`. + err.span_label( + span, + InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr) + ); } err @@ -496,19 +525,42 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr) = self.extract_type_name(&ty, None); + let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let mut err = struct_span_err!( self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr)); + err.span_label(span, InferCtxt::missing_type_msg( + &name, + &descr, + parent_name, + parent_descr + )); err } - fn missing_type_msg(type_name: &str, descr: &str) -> Cow<'static, str>{ + fn missing_type_msg( + type_name: &str, + descr: &str, + parent_name: Option, + parent_descr: Option<&str>, + ) -> Cow<'static, str> { if type_name == "_" { "cannot infer type".into() } else { - format!("cannot infer type for {} `{}`", descr, type_name).into() + let parent_desc = if let Some(parent_name) = parent_name { + let parent_type_descr = if let Some(parent_descr) = parent_descr { + format!(" the {}", parent_descr) + } else { + "".into() + }; + + format!(" declared on{} `{}`", parent_type_descr, parent_name) + } else { + "".to_string() + }; + + format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 73977878af337..996a722e157fa 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1135,7 +1135,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.universe(), false, TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(param.name), + kind: TypeVariableOriginKind::TypeParameterDefinition( + param.name, + Some(param.def_id) + ), span, }, ); diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 613f66d7ffd7e..ea4a28c22a9e7 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { if let ty::TyVar(ty_vid) = infer_ty { let ty_vars = self.infcx.type_variables.borrow(); if let TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(_), + kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), span, } = *ty_vars.var_origin(ty_vid) { diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index f79a30c7ae8f3..5a12de25f4b75 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -1,6 +1,7 @@ use syntax::symbol::Symbol; use syntax_pos::Span; use crate::ty::{self, Ty, TyVid}; +use crate::hir::def_id::DefId; use std::cmp; use std::marker::PhantomData; @@ -49,7 +50,7 @@ pub enum TypeVariableOriginKind { MiscVariable, NormalizeProjectionType, TypeInference, - TypeParameterDefinition(Symbol), + TypeParameterDefinition(Symbol, Option), /// One of the upvars or closure kind parameters in a `ClosureSubsts` /// (before it has been determined). diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index da36b31038de7..018bed9666487 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -2113,7 +2113,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var( TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(name), + kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), span: DUMMY_SP, } ) diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index b9b4f5133b9a7..3ffdb8ce6b9a1 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -2,7 +2,7 @@ error[E0698]: type inside `async fn` body must be known in this context --> $DIR/unresolved_type_param.rs:9:5 | LL | bar().await; - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the function `bar` | note: the type is part of the `async fn` body because of this `await` --> $DIR/unresolved_type_param.rs:9:5 diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr index 9ccad7bcdd7e6..44eab8baa40a6 100644 --- a/src/test/ui/const-generics/fn-const-param-infer.stderr +++ b/src/test/ui/const-generics/fn-const-param-infer.stderr @@ -30,7 +30,7 @@ error[E0282]: type annotations needed --> $DIR/fn-const-param-infer.rs:22:23 | LL | let _ = Checked::; - | ^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^ cannot infer type for type parameter `T` declared on the function `generic` error[E0308]: mismatched types --> $DIR/fn-const-param-infer.rs:25:40 diff --git a/src/test/ui/consts/issue-64662.stderr b/src/test/ui/consts/issue-64662.stderr index b3c673ec027ef..dd281e911da96 100644 --- a/src/test/ui/consts/issue-64662.stderr +++ b/src/test/ui/consts/issue-64662.stderr @@ -2,13 +2,13 @@ error[E0282]: type annotations needed --> $DIR/issue-64662.rs:2:9 | LL | A = foo(), - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the function `foo` error[E0282]: type annotations needed --> $DIR/issue-64662.rs:3:9 | LL | B = foo(), - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the function `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 0adf982d71c90..8b1d4e6c07ceb 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -36,7 +36,7 @@ error[E0282]: type annotations needed --> $DIR/E0401.rs:11:5 | LL | bfnr(x); - | ^^^^ cannot infer type for type parameter `U` + | ^^^^ cannot infer type for type parameter `U` declared on the function `bfnr` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 5f2dd729c739f..fe7e8f89f7f1a 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -2,7 +2,7 @@ error[E0284]: type annotations needed --> $DIR/issue-12028.rs:27:14 | LL | self.input_stream(&mut stream); - | ^^^^^^^^^^^^ cannot infer type for type parameter `H` + | ^^^^^^^^^^^^ cannot infer type for type parameter `H` declared on the trait `StreamHash` | = note: cannot resolve `<_ as StreamHasher>::S == ::S` diff --git a/src/test/ui/issues/issue-16966.stderr b/src/test/ui/issues/issue-16966.stderr index 0d565af79b5de..49a12cc200947 100644 --- a/src/test/ui/issues/issue-16966.stderr +++ b/src/test/ui/issues/issue-16966.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-16966.rs:2:5 | LL | panic!(std::default::Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `M` declared on the function `begin_panic` | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-17551.stderr b/src/test/ui/issues/issue-17551.stderr index 5468268e7de94..48405a292f3aa 100644 --- a/src/test/ui/issues/issue-17551.stderr +++ b/src/test/ui/issues/issue-17551.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `B` --> $DIR/issue-17551.rs:6:15 | LL | let foo = B(marker::PhantomData); - | --- ^ cannot infer type for type parameter `T` + | --- ^ cannot infer type for type parameter `T` declared on the struct `B` | | | consider giving `foo` the explicit type `B`, where the type parameter `T` is specified diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index de020d4b56ba1..a09de86a708f8 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -5,7 +5,7 @@ LL | let (tx, rx) = channel(); | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... LL | tx.send(Foo{ foo: PhantomData }); - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the struct `Foo` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5062.stderr b/src/test/ui/issues/issue-5062.stderr index a20118d691170..9fa15dc967914 100644 --- a/src/test/ui/issues/issue-5062.stderr +++ b/src/test/ui/issues/issue-5062.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-5062.rs:1:29 | LL | fn main() { format!("{:?}", None); } - | ^^^^ cannot infer type for type parameter `T` + | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458-2.stderr b/src/test/ui/issues/issue-6458-2.stderr index d538a69045f32..da16f95dc3de6 100644 --- a/src/test/ui/issues/issue-6458-2.stderr +++ b/src/test/ui/issues/issue-6458-2.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458-2.rs:3:21 | LL | format!("{:?}", None); - | ^^^^ cannot infer type for type parameter `T` + | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458-3.stderr b/src/test/ui/issues/issue-6458-3.stderr index 6b3f469ee3789..a71c159db0b0e 100644 --- a/src/test/ui/issues/issue-6458-3.stderr +++ b/src/test/ui/issues/issue-6458-3.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458-3.rs:4:5 | LL | mem::transmute(0); - | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` + | ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-6458.stderr b/src/test/ui/issues/issue-6458.stderr index de315659b6df9..f1a982616a4a1 100644 --- a/src/test/ui/issues/issue-6458.stderr +++ b/src/test/ui/issues/issue-6458.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/issue-6458.rs:9:4 | LL | foo(TypeWithState(marker::PhantomData)); - | ^^^ cannot infer type for type parameter `State` + | ^^^ cannot infer type for type parameter `State` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-items/missing-type-parameter.stderr b/src/test/ui/missing/missing-items/missing-type-parameter.stderr index be97f2373c313..1219badc5b3fc 100644 --- a/src/test/ui/missing/missing-items/missing-type-parameter.stderr +++ b/src/test/ui/missing/missing-items/missing-type-parameter.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/missing-type-parameter.rs:4:5 | LL | foo(); - | ^^^ cannot infer type for type parameter `X` + | ^^^ cannot infer type for type parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/span/type-annotations-needed-expr.stderr b/src/test/ui/span/type-annotations-needed-expr.stderr index 8366285edcda8..2b92f9b93bff2 100644 --- a/src/test/ui/span/type-annotations-needed-expr.stderr +++ b/src/test/ui/span/type-annotations-needed-expr.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | let _ = (vec![1,2,3]).into_iter().sum() as f64; | ^^^ | | - | cannot infer type for type parameter `S` + | cannot infer type for type parameter `S` declared on the method `sum` | help: consider specifying the type argument in the method call: `sum::` | = note: type must be known at this point diff --git a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr index 7bcda234c4b0d..338c8cbf2e4f2 100644 --- a/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr +++ b/src/test/ui/traits/traits-multidispatch-convert-ambig-dest.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/traits-multidispatch-convert-ambig-dest.rs:26:5 | LL | test(22, std::default::Default::default()); - | ^^^^ cannot infer type for type parameter `U` + | ^^^^ cannot infer type for type parameter `U` declared on the function `test` error: aborting due to previous error diff --git a/src/test/ui/type-inference/or_else-multiple-type-params.stderr b/src/test/ui/type-inference/or_else-multiple-type-params.stderr index 141cc25ffe22d..b9258b20f5add 100644 --- a/src/test/ui/type-inference/or_else-multiple-type-params.stderr +++ b/src/test/ui/type-inference/or_else-multiple-type-params.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | .or_else(|err| { | ^^^^^^^ | | - | cannot infer type for type parameter `F` + | cannot infer type for type parameter `F` declared on the method `or_else` | help: consider specifying the type arguments in the method call: `or_else::` error: aborting due to previous error diff --git a/src/test/ui/type-inference/sort_by_key.stderr b/src/test/ui/type-inference/sort_by_key.stderr index 1d386bd1f42c9..e74c0dfa5e20c 100644 --- a/src/test/ui/type-inference/sort_by_key.stderr +++ b/src/test/ui/type-inference/sort_by_key.stderr @@ -4,7 +4,7 @@ error[E0282]: type annotations needed LL | lst.sort_by_key(|&(v, _)| v.iter().sum()); | ^^^^^^^^^^^ --- help: consider specifying the type argument in the method call: `sum::` | | - | cannot infer type for type parameter `K` + | cannot infer type for type parameter `K` declared on the method `sort_by_key` error: aborting due to previous error diff --git a/src/test/ui/type-inference/unbounded-associated-type.stderr b/src/test/ui/type-inference/unbounded-associated-type.stderr index 726dd4b475817..19e2bd4513dc5 100644 --- a/src/test/ui/type-inference/unbounded-associated-type.stderr +++ b/src/test/ui/type-inference/unbounded-associated-type.stderr @@ -8,7 +8,7 @@ LL | S(std::marker::PhantomData).foo(); | ^-------------------------------- | | | this method call resolves to `::A` - | cannot infer type for type parameter `X` + | cannot infer type for type parameter `X` declared on the struct `S` error: aborting due to previous error diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr index 52039d0e934e6..d60ca4a49325c 100644 --- a/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn-with-assoc-type.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unbounded-type-param-in-fn-with-assoc-type.rs:8:5 | LL | foo(); - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr index 8d317df6ce95a..45d879d8d5670 100644 --- a/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr +++ b/src/test/ui/type-inference/unbounded-type-param-in-fn.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unbounded-type-param-in-fn.rs:6:5 | LL | foo(); - | ^^^ cannot infer type for type parameter `T` + | ^^^ cannot infer type for type parameter `T` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 94425440d333c..c6a811e836342 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -7,7 +7,7 @@ LL | fn foo>(x: i32) {} LL | foo(42); | ^^^ | | - | cannot infer type for type parameter `T` + | cannot infer type for type parameter `T` declared on the function `foo` | help: consider specifying the type argument in the function call: `foo::` | = note: cannot resolve `_: std::convert::Into` diff --git a/src/test/ui/unconstrained-none.stderr b/src/test/ui/unconstrained-none.stderr index 6c4fde94a6199..fbd71bd091d0b 100644 --- a/src/test/ui/unconstrained-none.stderr +++ b/src/test/ui/unconstrained-none.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-none.rs:4:5 | LL | None; - | ^^^^ cannot infer type for type parameter `T` + | ^^^^ cannot infer type for type parameter `T` declared on the enum `Option` error: aborting due to previous error diff --git a/src/test/ui/unconstrained-ref.stderr b/src/test/ui/unconstrained-ref.stderr index d6985a61daf0b..eb8ebb5165d18 100644 --- a/src/test/ui/unconstrained-ref.stderr +++ b/src/test/ui/unconstrained-ref.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/unconstrained-ref.rs:6:5 | LL | S { o: &None }; - | ^ cannot infer type for type parameter `T` + | ^ cannot infer type for type parameter `T` declared on the struct `S` error: aborting due to previous error From 6ad0b55597d58f65b775cc32588d5cb396993c0c Mon Sep 17 00:00:00 2001 From: Robin Kruppe Date: Sun, 15 Dec 2019 18:17:00 +0100 Subject: [PATCH 04/14] Remove now-redundant range check on u128 -> f32 casts This code was added to avoid UB in LLVM 6 and earlier, but we no longer support those LLVM versions. Since https://reviews.llvm.org/D47807 (released in LLVM 7), uitofp does exactly what we need. Closes #51872 --- src/librustc_codegen_ssa/mir/rvalue.rs | 43 +++++--------------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 488ae8dbf9036..55d63f18cd906 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -341,6 +341,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llval } } + (CastTy::Int(_), CastTy::Float) => { + if signed { + bx.sitofp(llval, ll_t_out) + } else { + bx.uitofp(llval, ll_t_out) + } + } (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_)) | (CastTy::RPtr(_), CastTy::Ptr(_)) => @@ -352,8 +359,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed); bx.inttoptr(usize_llval, ll_t_out) } - (CastTy::Int(_), CastTy::Float) => - cast_int_to_float(&mut bx, signed, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(IntTy::I)) => cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out), (CastTy::Float, CastTy::Int(_)) => @@ -720,40 +725,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } -fn cast_int_to_float<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - signed: bool, - x: Bx::Value, - int_ty: Bx::Type, - float_ty: Bx::Type -) -> Bx::Value { - // Most integer types, even i128, fit into [-f32::MAX, f32::MAX] after rounding. - // It's only u128 -> f32 that can cause overflows (i.e., should yield infinity). - // LLVM's uitofp produces undef in those cases, so we manually check for that case. - let is_u128_to_f32 = !signed && - bx.cx().int_width(int_ty) == 128 && - bx.cx().float_width(float_ty) == 32; - if is_u128_to_f32 { - // All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity, - // and for everything else LLVM's uitofp works just fine. - use rustc_apfloat::ieee::Single; - const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1) - << (Single::MAX_EXP - Single::PRECISION as i16); - let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP); - let overflow = bx.icmp(IntPredicate::IntUGE, x, max); - let infinity_bits = bx.cx().const_u32(ieee::Single::INFINITY.to_bits() as u32); - let infinity = bx.bitcast(infinity_bits, float_ty); - let fp = bx.uitofp(x, float_ty); - bx.select(overflow, infinity, fp) - } else { - if signed { - bx.sitofp(x, float_ty) - } else { - bx.uitofp(x, float_ty) - } - } -} - fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, signed: bool, From 232022ff176bc77d19137ba7b3a40b73b403df9b Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Tue, 10 Dec 2019 23:32:52 -0800 Subject: [PATCH 05/14] Fix up Command Debug output when arg0 is specified. PR https://github.com/rust-lang/rust/pull/66512 added the ability to set argv[0] on Command. As a side effect, it changed the Debug output to print both the program and argv[0], which in practice results in stuttery output ("echo echo foo"). This PR reverts the behaviour to the the old one, so that the command is only printed once - unless arg0 has been set. In that case it emits "[command] arg0 arg1 ...". --- src/libstd/sys/unix/process/process_common.rs | 8 +++++-- src/test/ui/command-argv0-debug.rs | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/command-argv0-debug.rs diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index c9109b0c9d4d7..e66d6fdc56ac6 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -375,8 +375,12 @@ impl ChildStdio { impl fmt::Debug for Command { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.program)?; - for arg in &self.args { + if self.program != self.args[0] { + write!(f, "[{:?}] ", self.program)?; + } + write!(f, "{:?}", self.args[0])?; + + for arg in &self.args[1..] { write!(f, " {:?}", arg)?; } Ok(()) diff --git a/src/test/ui/command-argv0-debug.rs b/src/test/ui/command-argv0-debug.rs new file mode 100644 index 0000000000000..133d2ada2b263 --- /dev/null +++ b/src/test/ui/command-argv0-debug.rs @@ -0,0 +1,24 @@ +// run-pass + +// ignore-windows - this is a unix-specific test +// ignore-cloudabi no processes +// ignore-emscripten no processes +// ignore-sgx no processes +#![feature(process_set_argv0)] + +use std::os::unix::process::CommandExt; +use std::process::Command; + +fn main() { + let mut command = Command::new("some-boring-name"); + + assert_eq!(format!("{:?}", command), r#""some-boring-name""#); + + command.args(&["1", "2", "3"]); + + assert_eq!(format!("{:?}", command), r#""some-boring-name" "1" "2" "3""#); + + command.arg0("exciting-name"); + + assert_eq!(format!("{:?}", command), r#"["some-boring-name"] "exciting-name" "1" "2" "3""#); +} From ce56e7528359b9581cac0b59080d25468d60de20 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Wed, 11 Dec 2019 21:39:57 -0800 Subject: [PATCH 06/14] Move command-related tests into command/ --- src/test/ui/{ => command}/command-argv0-debug.rs | 0 src/test/ui/{ => command}/command-argv0.rs | 0 src/test/ui/{ => command}/command-exec.rs | 0 src/test/ui/{ => command}/command-pre-exec.rs | 0 src/test/ui/{ => command}/command-uid-gid.rs | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => command}/command-argv0-debug.rs (100%) rename src/test/ui/{ => command}/command-argv0.rs (100%) rename src/test/ui/{ => command}/command-exec.rs (100%) rename src/test/ui/{ => command}/command-pre-exec.rs (100%) rename src/test/ui/{ => command}/command-uid-gid.rs (100%) diff --git a/src/test/ui/command-argv0-debug.rs b/src/test/ui/command/command-argv0-debug.rs similarity index 100% rename from src/test/ui/command-argv0-debug.rs rename to src/test/ui/command/command-argv0-debug.rs diff --git a/src/test/ui/command-argv0.rs b/src/test/ui/command/command-argv0.rs similarity index 100% rename from src/test/ui/command-argv0.rs rename to src/test/ui/command/command-argv0.rs diff --git a/src/test/ui/command-exec.rs b/src/test/ui/command/command-exec.rs similarity index 100% rename from src/test/ui/command-exec.rs rename to src/test/ui/command/command-exec.rs diff --git a/src/test/ui/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs similarity index 100% rename from src/test/ui/command-pre-exec.rs rename to src/test/ui/command/command-pre-exec.rs diff --git a/src/test/ui/command-uid-gid.rs b/src/test/ui/command/command-uid-gid.rs similarity index 100% rename from src/test/ui/command-uid-gid.rs rename to src/test/ui/command/command-uid-gid.rs From 17aa0cb2ca73ad789e718bf9162a740af02a829f Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 14:44:19 -0600 Subject: [PATCH 07/14] Remove a const-if-hack in RawVec --- src/liballoc/raw_vec.rs | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ee75fc288fee5..dec990a117bf8 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -1,6 +1,8 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "0")] #![doc(hidden)] +#![feature(const_if_match)] + use core::cmp; use core::mem; use core::ops::Drop; @@ -51,15 +53,24 @@ pub struct RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[cfg(not(bootstrap))] pub const fn new_in(a: A) -> Self { - // `!0` is `usize::MAX`. This branch should be stripped at compile time. - // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: - //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { ptr: Unique::empty(), - // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap, + a, + } + } + + /// Like `new`, but parameterized over the choice of allocator for + /// the returned `RawVec`. + #[cfg(bootstrap)] + pub const fn new_in(a: A) -> Self { + RawVec { + ptr: Unique::empty(), cap: [0, !0][(mem::size_of::() == 0) as usize], a, } @@ -131,17 +142,30 @@ impl RawVec { /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. + #[cfg(not(bootstrap))] pub const fn new() -> Self { // FIXME(Centril): Reintegrate this with `fn new_in` when we can. - // `!0` is `usize::MAX`. This branch should be stripped at compile time. - // FIXME(mark-i-m): use this line when `if`s are allowed in `const`: - //let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = if mem::size_of::() == 0 { !0 } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { ptr: Unique::empty(), - // FIXME(mark-i-m): use `cap` when ifs are allowed in const + cap, + a: Global, + } + } + + /// Creates the biggest possible `RawVec` (on the system heap) + /// without allocating. If `T` has positive size, then this makes a + /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a + /// `RawVec` with capacity `usize::MAX`. Useful for implementing + /// delayed allocation. + #[cfg(bootstrap)] + pub const fn new() -> Self { + // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". + RawVec { + ptr: Unique::empty(), cap: [0, !0][(mem::size_of::() == 0) as usize], a: Global, } From 3ec3fca414f62cb3172b9324fe7aaa516c71b4e9 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 15:29:57 -0600 Subject: [PATCH 08/14] remove a bit more hackery --- src/liballoc/lib.rs | 1 + src/liballoc/raw_vec.rs | 49 +++++++---------------------------------- 2 files changed, 9 insertions(+), 41 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0137275bc1589..6e44c7631b3f0 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,6 +85,7 @@ #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] +#![cfg_attr(not(bootstrap), feature(const_if_match))] #![feature(cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index dec990a117bf8..ce192a7450c9d 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -1,8 +1,6 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "0")] #![doc(hidden)] -#![feature(const_if_match)] - use core::cmp; use core::mem; use core::ops::Drop; @@ -53,9 +51,14 @@ pub struct RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[cfg(not(bootstrap))] pub const fn new_in(a: A) -> Self { - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; + let cap = { + #[cfg(not(bootstrap))] + { if mem::size_of::() == 0 { !0 } else { 0 } } + + #[cfg(bootstrap)] + [0, !0][(mem::size_of::() == 0) as usize] + }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { @@ -65,17 +68,6 @@ impl RawVec { } } - /// Like `new`, but parameterized over the choice of allocator for - /// the returned `RawVec`. - #[cfg(bootstrap)] - pub const fn new_in(a: A) -> Self { - RawVec { - ptr: Unique::empty(), - cap: [0, !0][(mem::size_of::() == 0) as usize], - a, - } - } - /// Like `with_capacity`, but parameterized over the choice of /// allocator for the returned `RawVec`. #[inline] @@ -142,33 +134,8 @@ impl RawVec { /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a /// `RawVec` with capacity `usize::MAX`. Useful for implementing /// delayed allocation. - #[cfg(not(bootstrap))] - pub const fn new() -> Self { - // FIXME(Centril): Reintegrate this with `fn new_in` when we can. - - let cap = if mem::size_of::() == 0 { !0 } else { 0 }; - - // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". - RawVec { - ptr: Unique::empty(), - cap, - a: Global, - } - } - - /// Creates the biggest possible `RawVec` (on the system heap) - /// without allocating. If `T` has positive size, then this makes a - /// `RawVec` with capacity `0`. If `T` is zero-sized, then it makes a - /// `RawVec` with capacity `usize::MAX`. Useful for implementing - /// delayed allocation. - #[cfg(bootstrap)] pub const fn new() -> Self { - // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". - RawVec { - ptr: Unique::empty(), - cap: [0, !0][(mem::size_of::() == 0) as usize], - a: Global, - } + Self::new_in(Global) } /// Creates a `RawVec` (on the system heap) with exactly the From baaf864e07a8b8b99ed548c08606c1c7da74256b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Mon, 25 Nov 2019 18:14:46 -0600 Subject: [PATCH 09/14] use usize::MAX instead of !0 --- src/liballoc/raw_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index ce192a7450c9d..0d6fb25957432 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -54,7 +54,7 @@ impl RawVec { pub const fn new_in(a: A) -> Self { let cap = { #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { !0 } else { 0 } } + { if mem::size_of::() == 0 { usize::MAX } else { 0 } } #[cfg(bootstrap)] [0, !0][(mem::size_of::() == 0) as usize] From 951f041347529e504b132640d829914a0f7ef7c6 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 26 Nov 2019 11:03:53 -0600 Subject: [PATCH 10/14] fix import --- src/liballoc/raw_vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 0d6fb25957432..dff8364b84730 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -54,7 +54,7 @@ impl RawVec { pub const fn new_in(a: A) -> Self { let cap = { #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { usize::MAX } else { 0 } } + { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } #[cfg(bootstrap)] [0, !0][(mem::size_of::() == 0) as usize] From 253543560aa10f90607b23b5b12be3cfe28fdb1b Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Tue, 26 Nov 2019 11:06:53 -0600 Subject: [PATCH 11/14] add fixme --- src/liballoc/raw_vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index dff8364b84730..96de5185b88cd 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -52,6 +52,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. pub const fn new_in(a: A) -> Self { + // FIXME(mark-i-m): remove bootstrapping cfgs these after a cycle let cap = { #[cfg(not(bootstrap))] { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } From 7d268119f07aeb41a1abe093c3fd2434743ac228 Mon Sep 17 00:00:00 2001 From: Mark Mansi Date: Wed, 18 Dec 2019 12:04:47 -0600 Subject: [PATCH 12/14] no need to bootstrap --- src/liballoc/lib.rs | 2 +- src/liballoc/raw_vec.rs | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 6e44c7631b3f0..be46e632be45f 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -85,7 +85,7 @@ #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] -#![cfg_attr(not(bootstrap), feature(const_if_match))] +#![feature(const_if_match)] #![feature(cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 96de5185b88cd..3201c702abb29 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -52,14 +52,7 @@ impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. pub const fn new_in(a: A) -> Self { - // FIXME(mark-i-m): remove bootstrapping cfgs these after a cycle - let cap = { - #[cfg(not(bootstrap))] - { if mem::size_of::() == 0 { core::usize::MAX } else { 0 } } - - #[cfg(bootstrap)] - [0, !0][(mem::size_of::() == 0) as usize] - }; + let cap = if mem::size_of::() == 0 { core::usize::MAX } else { 0 }; // `Unique::empty()` doubles as "unallocated" and "zero-sized allocation". RawVec { From b82671112c6bc389399d148ffd5c9579658b7a4b Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 20 Dec 2019 04:27:28 +0100 Subject: [PATCH 13/14] Remove `SOCK_CLOEXEC` dummy variable on platforms that don't use it. --- src/libstd/sys/unix/net.rs | 25 +++++++++---------------- src/libstd/sys/vxworks/net.rs | 2 -- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 5d101ed1f2e2b..4c23aabf49741 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -18,16 +18,6 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; -// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on -// Linux currently (e.g., support doesn't exist on other platforms). In order to -// get name resolution to work and things to compile we just define a dummy -// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't -// actually ever used (the blocks below are wrapped in `if cfg!` as well. -#[cfg(target_os = "linux")] -use libc::SOCK_CLOEXEC; -#[cfg(not(target_os = "linux"))] -const SOCK_CLOEXEC: c_int = 0; - pub struct Socket(FileDesc); pub fn init() {} @@ -69,8 +59,9 @@ impl Socket { // this option, however, was added in 2.6.27, and we still support // 2.6.18 as a kernel, so if the returned error is EINVAL we // fallthrough to the fallback. - if cfg!(target_os = "linux") { - match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) { + #[cfg(target_os = "linux")] + { + match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) { Ok(fd) => return Ok(Socket(FileDesc::new(fd))), Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} Err(e) => return Err(e), @@ -96,8 +87,9 @@ impl Socket { let mut fds = [0, 0]; // Like above, see if we can set cloexec atomically - if cfg!(target_os = "linux") { - match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { + #[cfg(target_os = "linux")] + { + match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) { Ok(_) => { return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))); } @@ -187,7 +179,8 @@ impl Socket { // atomically set the CLOEXEC flag is to use the `accept4` syscall on // Linux. This was added in 2.6.28, however, and because we support // 2.6.18 we must detect this support dynamically. - if cfg!(target_os = "linux") { + #[cfg(target_os = "linux")] + { syscall! { fn accept4( fd: c_int, @@ -196,7 +189,7 @@ impl Socket { flags: c_int ) -> c_int } - let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, SOCK_CLOEXEC) }); + let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) }); match res { Ok(fd) => return Ok(Socket(FileDesc::new(fd))), Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index 54466ff2c2e07..74cbd246fe819 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -18,8 +18,6 @@ pub extern crate libc as netc; pub type wrlen_t = size_t; -const SOCK_CLOEXEC: c_int = 0; - pub struct Socket(FileDesc); pub fn init() {} From 83fc600a28044f8384bbce437c3251620f869254 Mon Sep 17 00:00:00 2001 From: Victor Ding Date: Tue, 17 Dec 2019 23:22:55 +1100 Subject: [PATCH 14/14] Move command line option definitions into a dedicated file config.rs has reached the 3000 line tidy limit, this commit moves command line option definitions into a new file - options.rs, and leaves the rest of configuration infrastructure in config.rs. --- src/librustc_session/config.rs | 939 +------------------------------ src/librustc_session/lib.rs | 3 + src/librustc_session/options.rs | 951 ++++++++++++++++++++++++++++++++ 3 files changed, 957 insertions(+), 936 deletions(-) create mode 100644 src/librustc_session/options.rs diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 7f3bab8f23299..55e647729e97f 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1,8 +1,8 @@ -// ignore-tidy-filelength - //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. +pub use crate::options::*; + use crate::lint; use crate::utils::NativeLibraryKind; use crate::{early_error, early_warn, Session}; @@ -11,7 +11,6 @@ use crate::search_paths::SearchPath; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; -use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use rustc_target::spec::{Target, TargetTriple}; use syntax_pos::source_map::{FileName, FilePathMapping}; @@ -31,8 +30,6 @@ use std::collections::btree_map::{ }; use std::fmt; use std::str::{self, FromStr}; -use std::hash::Hasher; -use std::collections::hash_map::DefaultHasher; use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; @@ -382,131 +379,6 @@ impl ExternEntry { } } -macro_rules! hash_option { - ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({}); - ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({ - if $sub_hashes.insert(stringify!($opt_name), - $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() { - panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name)) - } - }); -} - -macro_rules! top_level_options { - (pub struct Options { $( - $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*], - )* } ) => ( - #[derive(Clone)] - pub struct Options { - $(pub $opt: $t),* - } - - impl Options { - pub fn dep_tracking_hash(&self) -> u64 { - let mut sub_hashes = BTreeMap::new(); - $({ - hash_option!($opt, - &self.$opt, - &mut sub_hashes, - [$dep_tracking_marker $($warn_val, - $warn_text, - self.error_format)*]); - })* - let mut hasher = DefaultHasher::new(); - dep_tracking::stable_hash(sub_hashes, - &mut hasher, - self.error_format); - hasher.finish() - } - } - ); -} - -// The top-level command-line options struct. -// -// For each option, one has to specify how it behaves with regard to the -// dependency tracking system of incremental compilation. This is done via the -// square-bracketed directive after the field type. The options are: -// -// [TRACKED] -// A change in the given field will cause the compiler to completely clear the -// incremental compilation cache before proceeding. -// -// [UNTRACKED] -// Incremental compilation is not influenced by this option. -// -// If you add a new option to this struct or one of the sub-structs like -// `CodegenOptions`, think about how it influences incremental compilation. If in -// doubt, specify [TRACKED], which is always "correct" but might lead to -// unnecessary re-compilation. -top_level_options!( - pub struct Options { - // The crate config requested for the session, which may be combined - // with additional crate configurations during the compile process. - crate_types: Vec [TRACKED], - optimize: OptLevel [TRACKED], - // Include the `debug_assertions` flag in dependency tracking, since it - // can influence whether overflow checks are done or not. - debug_assertions: bool [TRACKED], - debuginfo: DebugInfo [TRACKED], - lint_opts: Vec<(String, lint::Level)> [TRACKED], - lint_cap: Option [TRACKED], - describe_lints: bool [UNTRACKED], - output_types: OutputTypes [TRACKED], - search_paths: Vec [UNTRACKED], - libs: Vec<(String, Option, Option)> [TRACKED], - maybe_sysroot: Option [UNTRACKED], - - target_triple: TargetTriple [TRACKED], - - test: bool [TRACKED], - error_format: ErrorOutputType [UNTRACKED], - - // If `Some`, enable incremental compilation, using the given - // directory to store intermediate results. - incremental: Option [UNTRACKED], - - debugging_opts: DebuggingOptions [TRACKED], - prints: Vec [UNTRACKED], - // Determines which borrow checker(s) to run. This is the parsed, sanitized - // version of `debugging_opts.borrowck`, which is just a plain string. - borrowck_mode: BorrowckMode [UNTRACKED], - cg: CodegenOptions [TRACKED], - externs: Externs [UNTRACKED], - crate_name: Option [TRACKED], - // An optional name to use as the crate for std during std injection, - // written `extern crate name as std`. Defaults to `std`. Used by - // out-of-tree drivers. - alt_std_name: Option [TRACKED], - // Indicates how the compiler should treat unstable features. - unstable_features: UnstableFeatures [TRACKED], - - // Indicates whether this run of the compiler is actually rustdoc. This - // is currently just a hack and will be removed eventually, so please - // try to not rely on this too much. - actually_rustdoc: bool [TRACKED], - - // Specifications of codegen units / ThinLTO which are forced as a - // result of parsing command line options. These are not necessarily - // what rustc was invoked with, but massaged a bit to agree with - // commands like `--emit llvm-ir` which they're often incompatible with - // if we otherwise use the defaults of rustc. - cli_forced_codegen_units: Option [UNTRACKED], - cli_forced_thinlto_off: bool [UNTRACKED], - - // Remap source path prefixes in all output (messages, object files, debug, etc.). - remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], - - edition: Edition [TRACKED], - - // `true` if we're emitting JSON blobs about each artifact produced - // by the compiler. - json_artifact_notifications: bool [TRACKED], - - pretty: Option [UNTRACKED], - } -); - #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PrintRequest { FileNames, @@ -767,811 +639,6 @@ impl Passes { } } -/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this -/// macro is to define an interface that can be programmatically used by the option parser -/// to initialize the struct without hardcoding field names all over the place. -/// -/// The goal is to invoke this macro once with the correct fields, and then this macro generates all -/// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of -/// generated code to parse an option into its respective field in the struct. There are a few -/// hand-written parsers for parsing specific types of values in this module. -macro_rules! options { - ($struct_name:ident, $setter_name:ident, $defaultfn:ident, - $buildfn:ident, $prefix:expr, $outputname:expr, - $stat:ident, $mod_desc:ident, $mod_set:ident, - $($opt:ident : $t:ty = ( - $init:expr, - $parse:ident, - [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*], - $desc:expr) - ),* ,) => -( - #[derive(Clone)] - pub struct $struct_name { $(pub $opt: $t),* } - - pub fn $defaultfn() -> $struct_name { - $struct_name { $($opt: $init),* } - } - - pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name - { - let mut op = $defaultfn(); - for option in matches.opt_strs($prefix) { - let mut iter = option.splitn(2, '='); - let key = iter.next().unwrap(); - let value = iter.next(); - let option_to_lookup = key.replace("-", "_"); - let mut found = false; - for &(candidate, setter, opt_type_desc, _) in $stat { - if option_to_lookup != candidate { continue } - if !setter(&mut op, value) { - match (value, opt_type_desc) { - (Some(..), None) => { - early_error(error_format, &format!("{} option `{}` takes no \ - value", $outputname, key)) - } - (None, Some(type_desc)) => { - early_error(error_format, &format!("{0} option `{1}` requires \ - {2} ({3} {1}=)", - $outputname, key, - type_desc, $prefix)) - } - (Some(value), Some(type_desc)) => { - early_error(error_format, &format!("incorrect value `{}` for {} \ - option `{}` - {} was expected", - value, $outputname, - key, type_desc)) - } - (None, None) => panic!() - } - } - found = true; - break; - } - if !found { - early_error(error_format, &format!("unknown {} option: `{}`", - $outputname, key)); - } - } - return op; - } - - impl dep_tracking::DepTrackingHash for $struct_name { - fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { - let mut sub_hashes = BTreeMap::new(); - $({ - hash_option!($opt, - &self.$opt, - &mut sub_hashes, - [$dep_tracking_marker $($dep_warn_val, - $dep_warn_text, - error_format)*]); - })* - dep_tracking::stable_hash(sub_hashes, hasher, error_format); - } - } - - pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool; - pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] = - &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ]; - - #[allow(non_upper_case_globals, dead_code)] - mod $mod_desc { - pub const parse_bool: Option<&str> = None; - pub const parse_opt_bool: Option<&str> = - Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); - pub const parse_string: Option<&str> = Some("a string"); - pub const parse_string_push: Option<&str> = Some("a string"); - pub const parse_pathbuf_push: Option<&str> = Some("a path"); - pub const parse_opt_string: Option<&str> = Some("a string"); - pub const parse_opt_pathbuf: Option<&str> = Some("a path"); - pub const parse_list: Option<&str> = Some("a space-separated list of strings"); - pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings"); - pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings"); - pub const parse_threads: Option<&str> = Some("a number"); - pub const parse_uint: Option<&str> = Some("a number"); - pub const parse_passes: Option<&str> = - Some("a space-separated list of passes, or `all`"); - pub const parse_opt_uint: Option<&str> = - Some("a number"); - pub const parse_panic_strategy: Option<&str> = - Some("either `unwind` or `abort`"); - pub const parse_relro_level: Option<&str> = - Some("one of: `full`, `partial`, or `off`"); - pub const parse_sanitizer: Option<&str> = - Some("one of: `address`, `leak`, `memory` or `thread`"); - pub const parse_sanitizer_list: Option<&str> = - Some("comma separated list of sanitizers"); - pub const parse_sanitizer_memory_track_origins: Option<&str> = None; - pub const parse_linker_flavor: Option<&str> = - Some(::rustc_target::spec::LinkerFlavor::one_of()); - pub const parse_optimization_fuel: Option<&str> = - Some("crate=integer"); - pub const parse_unpretty: Option<&str> = - Some("`string` or `string=string`"); - pub const parse_treat_err_as_bug: Option<&str> = - Some("either no value or a number bigger than 0"); - pub const parse_lto: Option<&str> = - Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ - `fat`, or omitted"); - pub const parse_linker_plugin_lto: Option<&str> = - Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \ - or the path to the linker plugin"); - pub const parse_switch_with_opt_path: Option<&str> = - Some("an optional path to the profiling data output directory"); - pub const parse_merge_functions: Option<&str> = - Some("one of: `disabled`, `trampolines`, or `aliases`"); - pub const parse_symbol_mangling_version: Option<&str> = - Some("either `legacy` or `v0` (RFC 2603)"); - } - - #[allow(dead_code)] - mod $mod_set { - use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, - SymbolManglingVersion}; - use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; - use std::path::PathBuf; - use std::str::FromStr; - - $( - pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { - $parse(&mut cg.$opt, v) - } - )* - - fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool { - match v { - Some(..) => false, - None => { *slot = true; true } - } - } - - fn parse_opt_bool(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { - match s { - "n" | "no" | "off" => { - *slot = Some(false); - } - "y" | "yes" | "on" => { - *slot = Some(true); - } - _ => { return false; } - } - - true - }, - None => { *slot = Some(true); true } - } - } - - fn parse_opt_string(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = Some(s.to_string()); true }, - None => false, - } - } - - fn parse_opt_pathbuf(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = Some(PathBuf::from(s)); true }, - None => false, - } - } - - fn parse_string(slot: &mut String, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.to_string(); true }, - None => false, - } - } - - fn parse_string_push(slot: &mut Vec, v: Option<&str>) -> bool { - match v { - Some(s) => { slot.push(s.to_string()); true }, - None => false, - } - } - - fn parse_pathbuf_push(slot: &mut Vec, v: Option<&str>) -> bool { - match v { - Some(s) => { slot.push(PathBuf::from(s)); true }, - None => false, - } - } - - fn parse_list(slot: &mut Vec, v: Option<&str>) - -> bool { - match v { - Some(s) => { - slot.extend(s.split_whitespace().map(|s| s.to_string())); - true - }, - None => false, - } - } - - fn parse_opt_list(slot: &mut Option>, v: Option<&str>) - -> bool { - match v { - Some(s) => { - let v = s.split_whitespace().map(|s| s.to_string()).collect(); - *slot = Some(v); - true - }, - None => false, - } - } - - fn parse_opt_comma_list(slot: &mut Option>, v: Option<&str>) - -> bool { - match v { - Some(s) => { - let v = s.split(',').map(|s| s.to_string()).collect(); - *slot = Some(v); - true - }, - None => false, - } - } - - fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { - match v.and_then(|s| s.parse().ok()) { - Some(0) => { *slot = ::num_cpus::get(); true }, - Some(i) => { *slot = i; true }, - None => false - } - } - - fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { - match v.and_then(|s| s.parse().ok()) { - Some(i) => { *slot = i; true }, - None => false - } - } - - fn parse_opt_uint(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.parse().ok(); slot.is_some() } - None => { *slot = None; false } - } - } - - fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { - match v { - Some("all") => { - *slot = Passes::All; - true - } - v => { - let mut passes = vec![]; - if parse_list(&mut passes, v) { - *slot = Passes::Some(passes); - true - } else { - false - } - } - } - } - - fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some("unwind") => *slot = Some(PanicStrategy::Unwind), - Some("abort") => *slot = Some(PanicStrategy::Abort), - _ => return false - } - true - } - - fn parse_relro_level(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { - match s.parse::() { - Ok(level) => *slot = Some(level), - _ => return false - } - }, - _ => return false - } - true - } - - fn parse_sanitizer(slot: &mut Option, v: Option<&str>) -> bool { - if let Some(Ok(s)) = v.map(str::parse) { - *slot = Some(s); - true - } else { - false - } - } - - fn parse_sanitizer_list(slot: &mut Vec, v: Option<&str>) -> bool { - if let Some(v) = v { - for s in v.split(',').map(str::parse) { - if let Ok(s) = s { - if !slot.contains(&s) { - slot.push(s); - } - } else { - return false; - } - } - true - } else { - false - } - } - - fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool { - match v.map(|s| s.parse()) { - None => { - *slot = 2; - true - } - Some(Ok(i)) if i <= 2 => { - *slot = i; - true - } - _ => { - false - } - } - } - - fn parse_linker_flavor(slote: &mut Option, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavor::from_str) { - Some(lf) => *slote = Some(lf), - _ => return false, - } - true - } - - fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { - match v { - None => false, - Some(s) => { - let parts = s.split('=').collect::>(); - if parts.len() != 2 { return false; } - let crate_name = parts[0].to_string(); - let fuel = parts[1].parse::(); - if fuel.is_err() { return false; } - *slot = Some((crate_name, fuel.unwrap())); - true - } - } - } - - fn parse_unpretty(slot: &mut Option, v: Option<&str>) -> bool { - match v { - None => false, - Some(s) if s.split('=').count() <= 2 => { - *slot = Some(s.to_string()); - true - } - _ => false, - } - } - - fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { - match v { - Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } - None => { *slot = Some(1); true } - } - } - - fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - LtoCli::Yes - } else { - LtoCli::No - }; - return true - } - } - - *slot = match v { - None => LtoCli::NoParam, - Some("thin") => LtoCli::Thin, - Some("fat") => LtoCli::Fat, - Some(_) => return false, - }; - true - } - - fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool { - if v.is_some() { - let mut bool_arg = None; - if parse_opt_bool(&mut bool_arg, v) { - *slot = if bool_arg.unwrap() { - LinkerPluginLto::LinkerPluginAuto - } else { - LinkerPluginLto::Disabled - }; - return true - } - } - - *slot = match v { - None => LinkerPluginLto::LinkerPluginAuto, - Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)), - }; - true - } - - fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool { - *slot = match v { - None => SwitchWithOptPath::Enabled(None), - Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))), - }; - true - } - - fn parse_merge_functions(slot: &mut Option, v: Option<&str>) -> bool { - match v.and_then(|s| MergeFunctions::from_str(s).ok()) { - Some(mergefunc) => *slot = Some(mergefunc), - _ => return false, - } - true - } - - fn parse_symbol_mangling_version( - slot: &mut SymbolManglingVersion, - v: Option<&str>, - ) -> bool { - *slot = match v { - Some("legacy") => SymbolManglingVersion::Legacy, - Some("v0") => SymbolManglingVersion::V0, - _ => return false, - }; - true - } - } -) } - -options! {CodegenOptions, CodegenSetter, basic_codegen_options, - build_codegen_options, "C", "codegen", - CG_OPTIONS, cg_type_desc, cgsetters, - ar: Option = (None, parse_opt_string, [UNTRACKED], - "this option is deprecated and does nothing"), - linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], - "system linker to link outputs with"), - link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], - "a single extra argument to append to the linker invocation (can be used several times)"), - link_args: Option> = (None, parse_opt_list, [UNTRACKED], - "extra arguments to append to the linker invocation (space separated)"), - link_dead_code: bool = (false, parse_bool, [UNTRACKED], - "don't let linker strip dead code (turning it on can be used for code coverage)"), - lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED], - "perform LLVM link-time optimizations"), - target_cpu: Option = (None, parse_opt_string, [TRACKED], - "select target processor (`rustc --print target-cpus` for details)"), - target_feature: String = (String::new(), parse_string, [TRACKED], - "target specific attributes. (`rustc --print target-features` for details). \ - This feature is unsafe."), - passes: Vec = (Vec::new(), parse_list, [TRACKED], - "a list of extra LLVM passes to run (space separated)"), - llvm_args: Vec = (Vec::new(), parse_list, [TRACKED], - "a list of arguments to pass to LLVM (space separated)"), - save_temps: bool = (false, parse_bool, [UNTRACKED], - "save all temporary output files during compilation"), - rpath: bool = (false, parse_bool, [UNTRACKED], - "set rpath values in libs/exes"), - overflow_checks: Option = (None, parse_opt_bool, [TRACKED], - "use overflow checks for integer arithmetic"), - no_prepopulate_passes: bool = (false, parse_bool, [TRACKED], - "don't pre-populate the pass manager with a list of passes"), - no_vectorize_loops: bool = (false, parse_bool, [TRACKED], - "don't run the loop vectorization optimization passes"), - no_vectorize_slp: bool = (false, parse_bool, [TRACKED], - "don't run LLVM's SLP vectorization pass"), - soft_float: bool = (false, parse_bool, [TRACKED], - "use soft float ABI (*eabihf targets only)"), - prefer_dynamic: bool = (false, parse_bool, [TRACKED], - "prefer dynamic linking to static linking"), - no_integrated_as: bool = (false, parse_bool, [TRACKED], - "use an external assembler rather than LLVM's integrated one"), - no_redzone: Option = (None, parse_opt_bool, [TRACKED], - "disable the use of the redzone"), - relocation_model: Option = (None, parse_opt_string, [TRACKED], - "choose the relocation model to use (`rustc --print relocation-models` for details)"), - code_model: Option = (None, parse_opt_string, [TRACKED], - "choose the code model to use (`rustc --print code-models` for details)"), - metadata: Vec = (Vec::new(), parse_list, [TRACKED], - "metadata to mangle symbol names with"), - extra_filename: String = (String::new(), parse_string, [UNTRACKED], - "extra data to put in each output filename"), - codegen_units: Option = (None, parse_opt_uint, [UNTRACKED], - "divide crate into N units to optimize in parallel"), - remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED], - "print remarks for these optimization passes (space separated, or \"all\")"), - no_stack_check: bool = (false, parse_bool, [UNTRACKED], - "the `--no-stack-check` flag is deprecated and does nothing"), - debuginfo: Option = (None, parse_opt_uint, [TRACKED], - "debug info emission level, 0 = no debug info, 1 = line tables only, \ - 2 = full debug info with variable and type information"), - opt_level: Option = (None, parse_opt_string, [TRACKED], - "optimize with possible levels 0-3, s, or z"), - force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], - "force use of the frame pointers"), - debug_assertions: Option = (None, parse_opt_bool, [TRACKED], - "explicitly enable the `cfg(debug_assertions)` directive"), - inline_threshold: Option = (None, parse_opt_uint, [TRACKED], - "set the threshold for inlining a function (default: 225)"), - panic: Option = (None, parse_panic_strategy, - [TRACKED], "panic strategy to compile crate with"), - incremental: Option = (None, parse_opt_string, [UNTRACKED], - "enable incremental compilation"), - default_linker_libraries: Option = (None, parse_opt_bool, [UNTRACKED], - "allow the linker to link its default libraries"), - linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], - "linker flavor"), - linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, - parse_linker_plugin_lto, [TRACKED], - "generate build artifacts that are compatible with linker-based LTO."), - profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled, - parse_switch_with_opt_path, [TRACKED], - "compile the program with profiling instrumentation"), - profile_use: Option = (None, parse_opt_pathbuf, [TRACKED], - "use the given `.profdata` file for profile-guided optimization"), -} - -options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, - build_debugging_options, "Z", "debugging", - DB_OPTIONS, db_type_desc, dbsetters, - codegen_backend: Option = (None, parse_opt_string, [TRACKED], - "the backend to use"), - verbose: bool = (false, parse_bool, [UNTRACKED], - "in general, enable more debug printouts"), - span_free_formats: bool = (false, parse_bool, [UNTRACKED], - "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path - identify_regions: bool = (false, parse_bool, [UNTRACKED], - "make unnamed regions display as '# (where # is some non-ident unique id)"), - borrowck: Option = (None, parse_opt_string, [UNTRACKED], - "select which borrowck is used (`mir` or `migrate`)"), - time_passes: bool = (false, parse_bool, [UNTRACKED], - "measure time of each rustc pass"), - time: bool = (false, parse_bool, [UNTRACKED], - "measure time of rustc processes"), - time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], - "measure time of each LLVM pass"), - input_stats: bool = (false, parse_bool, [UNTRACKED], - "gather statistics about the input"), - asm_comments: bool = (false, parse_bool, [TRACKED], - "generate comments into the assembly (may change behavior)"), - verify_llvm_ir: bool = (false, parse_bool, [TRACKED], - "verify LLVM IR"), - borrowck_stats: bool = (false, parse_bool, [UNTRACKED], - "gather borrowck statistics"), - no_landing_pads: bool = (false, parse_bool, [TRACKED], - "omit landing pads for unwinding"), - fewer_names: bool = (false, parse_bool, [TRACKED], - "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"), - meta_stats: bool = (false, parse_bool, [UNTRACKED], - "gather metadata statistics"), - print_link_args: bool = (false, parse_bool, [UNTRACKED], - "print the arguments passed to the linker"), - print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], - "prints the LLVM optimization passes being run"), - ast_json: bool = (false, parse_bool, [UNTRACKED], - "print the AST as JSON and halt"), - // We default to 1 here since we want to behave like - // a sequential compiler for now. This'll likely be adjusted - // in the future. Note that -Zthreads=0 is the way to get - // the num_cpus behavior. - threads: usize = (1, parse_threads, [UNTRACKED], - "use a thread pool with N threads"), - ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], - "print the pre-expansion AST as JSON and halt"), - ls: bool = (false, parse_bool, [UNTRACKED], - "list the symbols defined by a library crate"), - save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information, in \ - addition to normal output"), - print_region_graph: bool = (false, parse_bool, [UNTRACKED], - "prints region inference graph. \ - Use with RUST_REGION_GRAPH=help for more info"), - parse_only: bool = (false, parse_bool, [UNTRACKED], - "parse only; do not compile, assemble, or link"), - dual_proc_macros: bool = (false, parse_bool, [TRACKED], - "load proc macros for both target and host, but only link to the target"), - no_codegen: bool = (false, parse_bool, [TRACKED], - "run all passes except codegen; no output"), - treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], - "treat error number `val` that occurs as bug"), - report_delayed_bugs: bool = (false, parse_bool, [TRACKED], - "immediately print bugs registered with `delay_span_bug`"), - external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], - "show macro backtraces even for non-local macros"), - teach: bool = (false, parse_bool, [TRACKED], - "show extended diagnostic help"), - terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], - "set the current terminal width"), - panic_abort_tests: bool = (false, parse_bool, [TRACKED], - "support compiling tests with panic=abort"), - continue_parse_after_error: bool = (false, parse_bool, [TRACKED], - "attempt to recover from parse errors (experimental)"), - dep_tasks: bool = (false, parse_bool, [UNTRACKED], - "print tasks that execute and the color their dep node gets (requires debug build)"), - incremental: Option = (None, parse_opt_string, [UNTRACKED], - "enable incremental compilation (experimental)"), - incremental_queries: bool = (true, parse_bool, [UNTRACKED], - "enable incremental compilation support for queries (experimental)"), - incremental_info: bool = (false, parse_bool, [UNTRACKED], - "print high-level information about incremental reuse (or the lack thereof)"), - incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], - "dump hash information in textual format to stdout"), - incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], - "verify incr. comp. hashes of green query instances"), - incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED], - "ignore spans during ICH computation -- used for testing"), - instrument_mcount: bool = (false, parse_bool, [TRACKED], - "insert function instrument code for mcount-based tracing"), - dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], - "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), - query_dep_graph: bool = (false, parse_bool, [UNTRACKED], - "enable queries of the dependency graph for regression testing"), - no_analysis: bool = (false, parse_bool, [UNTRACKED], - "parse and expand the source, but run no analysis"), - unstable_options: bool = (false, parse_bool, [UNTRACKED], - "adds unstable command line options to rustc interface"), - force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], - "force overflow checks on or off"), - trace_macros: bool = (false, parse_bool, [UNTRACKED], - "for every macro invocation, print its name and arguments"), - debug_macros: bool = (false, parse_bool, [TRACKED], - "emit line numbers debug info inside macros"), - generate_arange_section: bool = (true, parse_bool, [TRACKED], - "generate DWARF address ranges for faster lookups"), - keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], - "don't clear the hygiene data after analysis"), - keep_ast: bool = (false, parse_bool, [UNTRACKED], - "keep the AST after lowering it to HIR"), - show_span: Option = (None, parse_opt_string, [TRACKED], - "show spans for compiler debugging (expr|pat|ty)"), - print_type_sizes: bool = (false, parse_bool, [UNTRACKED], - "print layout information for each type encountered"), - print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], - "print the result of the monomorphization collection pass"), - mir_opt_level: usize = (1, parse_uint, [TRACKED], - "set the MIR optimization level (0-3, default: 1)"), - mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], - "emit noalias metadata for mutable references (default: no)"), - dump_mir: Option = (None, parse_opt_string, [UNTRACKED], - "dump MIR state to file. - `val` is used to select which passes and functions to dump. For example: - `all` matches all passes and functions, - `foo` matches all passes for functions whose name contains 'foo', - `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', - `foo | bar` all passes for function names containing 'foo' or 'bar'."), - - dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED], - "the directory the MIR is dumped into"), - dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], - "in addition to `.mir` files, create graphviz `.dot` files"), - dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], - "if set, exclude the pass number when dumping MIR (used in tests)"), - mir_emit_retag: bool = (false, parse_bool, [TRACKED], - "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"), - perf_stats: bool = (false, parse_bool, [UNTRACKED], - "print some performance-related statistics"), - query_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about the query system"), - hir_stats: bool = (false, parse_bool, [UNTRACKED], - "print some statistics about AST and HIR"), - always_encode_mir: bool = (false, parse_bool, [TRACKED], - "encode MIR of all functions into the crate metadata"), - json_rendered: Option = (None, parse_opt_string, [UNTRACKED], - "describes how to render the `rendered` field of json diagnostics"), - unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], - "take the breaks off const evaluation. NOTE: this is unsound"), - osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], - "pass `-install_name @rpath/...` to the macOS linker"), - sanitizer: Option = (None, parse_sanitizer, [TRACKED], - "use a sanitizer"), - sanitizer_recover: Vec = (vec![], parse_sanitizer_list, [TRACKED], - "Enable recovery for selected sanitizers"), - sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], - "Enable origins tracking in MemorySanitizer"), - fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], - "set the optimization fuel quota for a crate"), - print_fuel: Option = (None, parse_opt_string, [TRACKED], - "make rustc print the total optimization fuel used by a crate"), - force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], - "force all crates to be `rustc_private` unstable"), - pre_link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], - "a single extra argument to prepend the linker invocation (can be used several times)"), - pre_link_args: Option> = (None, parse_opt_list, [UNTRACKED], - "extra arguments to prepend to the linker invocation (space separated)"), - profile: bool = (false, parse_bool, [TRACKED], - "insert profiling code"), - disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED], - "Disable the instrumentation pre-inliner, useful for profiling / PGO."), - relro_level: Option = (None, parse_relro_level, [TRACKED], - "choose which RELRO level to use"), - nll_facts: bool = (false, parse_bool, [UNTRACKED], - "dump facts from NLL analysis into side files"), - nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED], - "in match codegen, do not include FakeRead statements (used by mir-borrowck)"), - dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], - "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."), - polonius: bool = (false, parse_bool, [UNTRACKED], - "enable polonius-based borrow-checker"), - codegen_time_graph: bool = (false, parse_bool, [UNTRACKED], - "generate a graphical HTML report of time spent in codegen and LLVM"), - thinlto: Option = (None, parse_opt_bool, [TRACKED], - "enable ThinLTO when possible"), - inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], - "control whether `#[inline]` functions are in all CGUs"), - tls_model: Option = (None, parse_opt_string, [TRACKED], - "choose the TLS model to use (`rustc --print tls-models` for details)"), - saturating_float_casts: bool = (false, parse_bool, [TRACKED], - "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ - the max/min integer respectively, and NaN is mapped to 0"), - human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], - "generate human-readable, predictable names for codegen units"), - dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], - "in dep-info output, omit targets for tracking dependencies of the dep-info files \ - themselves"), - unpretty: Option = (None, parse_unpretty, [UNTRACKED], - "present the input source, unstable (and less-pretty) variants; - valid types are any of the types for `--pretty`, as well as: - `expanded`, `expanded,identified`, - `expanded,hygiene` (with internal representations), - `everybody_loops` (all function bodies replaced with `loop {}`), - `hir` (the HIR), `hir,identified`, - `hir,typed` (HIR with types for each node), - `hir-tree` (dump the raw HIR), - `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), - run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], - "run `dsymutil` and delete intermediate object files"), - ui_testing: bool = (false, parse_bool, [UNTRACKED], - "format compiler diagnostics in a way that's better suitable for UI testing"), - embed_bitcode: bool = (false, parse_bool, [TRACKED], - "embed LLVM bitcode in object files"), - strip_debuginfo_if_disabled: Option = (None, parse_opt_bool, [TRACKED], - "tell the linker to strip debuginfo when building without debuginfo enabled."), - share_generics: Option = (None, parse_opt_bool, [TRACKED], - "make the current crate share its generic instantiations"), - chalk: bool = (false, parse_bool, [TRACKED], - "enable the experimental Chalk-based trait solving engine"), - no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED], - "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"), - no_leak_check: bool = (false, parse_bool, [UNTRACKED], - "disables the 'leak check' for subtyping; unsound, but useful for tests"), - no_interleave_lints: bool = (false, parse_bool, [UNTRACKED], - "don't interleave execution of lints; allows benchmarking individual lints"), - crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], - "inject the given attribute in the crate"), - self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, - parse_switch_with_opt_path, [UNTRACKED], - "run the self profiler and output the raw event data"), - self_profile_events: Option> = (None, parse_opt_comma_list, [UNTRACKED], - "specifies which kinds of events get recorded by the self profiler"), - emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], - "emits a section containing stack size metadata"), - plt: Option = (None, parse_opt_bool, [TRACKED], - "whether to use the PLT when calling into shared libraries; - only has effect for PIC code on systems with ELF binaries - (default: PLT is disabled if full relro is enabled)"), - merge_functions: Option = (None, parse_merge_functions, [TRACKED], - "control the operation of the MergeFunctions LLVM pass, taking - the same values as the target option of the same name"), - allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], - "only allow the listed language features to be enabled in code (space separated)"), - symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, - parse_symbol_mangling_version, [TRACKED], - "which mangling version to use for symbol names"), - binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], - "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"), - insert_sideeffect: bool = (false, parse_bool, [TRACKED], - "fix undefined behavior when a thread doesn't eventually make progress \ - (such as entering an empty infinite loop) by inserting llvm.sideeffect"), -} - pub const fn default_lib_output() -> CrateType { CrateType::Rlib } @@ -2953,7 +2020,7 @@ impl PpMode { /// `Hash` implementation for `DepTrackingHash`. It's important though that /// we have an opt-in scheme here, so one is hopefully forced to think about /// how the hash should be calculated when adding a new command-line argument. -mod dep_tracking { +crate mod dep_tracking { use crate::lint; use crate::utils::NativeLibraryKind; use std::collections::BTreeMap; diff --git a/src/librustc_session/lib.rs b/src/librustc_session/lib.rs index 9d7c23100a0fe..39e997a3b91ac 100644 --- a/src/librustc_session/lib.rs +++ b/src/librustc_session/lib.rs @@ -1,3 +1,4 @@ +#![feature(crate_visibility_modifier)] #![feature(test)] // Use the test crate here so we depend on getopts through it. This allow tools to link to both @@ -13,7 +14,9 @@ pub mod node_id; pub mod parse; mod code_stats; +#[macro_use] pub mod config; +mod options; pub mod filesearch; pub mod search_paths; diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs new file mode 100644 index 0000000000000..9ddc9c0d602af --- /dev/null +++ b/src/librustc_session/options.rs @@ -0,0 +1,951 @@ +use crate::config::*; + +use crate::lint; +use crate::utils::NativeLibraryKind; +use crate::early_error; +use crate::search_paths::SearchPath; + +use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; +use rustc_target::spec::TargetTriple; + +use syntax_pos::edition::Edition; +use rustc_feature::UnstableFeatures; + +use getopts; + +use std::collections::BTreeMap; + +use std::str; +use std::hash::Hasher; +use std::collections::hash_map::DefaultHasher; +use std::path::PathBuf; + +macro_rules! hash_option { + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({}); + ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({ + if $sub_hashes.insert(stringify!($opt_name), + $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() { + panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name)) + } + }); +} + +macro_rules! top_level_options { + (pub struct Options { $( + $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*], + )* } ) => ( + #[derive(Clone)] + pub struct Options { + $(pub $opt: $t),* + } + + impl Options { + pub fn dep_tracking_hash(&self) -> u64 { + let mut sub_hashes = BTreeMap::new(); + $({ + hash_option!($opt, + &self.$opt, + &mut sub_hashes, + [$dep_tracking_marker $($warn_val, + $warn_text, + self.error_format)*]); + })* + let mut hasher = DefaultHasher::new(); + dep_tracking::stable_hash(sub_hashes, + &mut hasher, + self.error_format); + hasher.finish() + } + } + ); +} + +// The top-level command-line options struct. +// +// For each option, one has to specify how it behaves with regard to the +// dependency tracking system of incremental compilation. This is done via the +// square-bracketed directive after the field type. The options are: +// +// [TRACKED] +// A change in the given field will cause the compiler to completely clear the +// incremental compilation cache before proceeding. +// +// [UNTRACKED] +// Incremental compilation is not influenced by this option. +// +// If you add a new option to this struct or one of the sub-structs like +// `CodegenOptions`, think about how it influences incremental compilation. If in +// doubt, specify [TRACKED], which is always "correct" but might lead to +// unnecessary re-compilation. +top_level_options!( + pub struct Options { + // The crate config requested for the session, which may be combined + // with additional crate configurations during the compile process. + crate_types: Vec [TRACKED], + optimize: OptLevel [TRACKED], + // Include the `debug_assertions` flag in dependency tracking, since it + // can influence whether overflow checks are done or not. + debug_assertions: bool [TRACKED], + debuginfo: DebugInfo [TRACKED], + lint_opts: Vec<(String, lint::Level)> [TRACKED], + lint_cap: Option [TRACKED], + describe_lints: bool [UNTRACKED], + output_types: OutputTypes [TRACKED], + search_paths: Vec [UNTRACKED], + libs: Vec<(String, Option, Option)> [TRACKED], + maybe_sysroot: Option [UNTRACKED], + + target_triple: TargetTriple [TRACKED], + + test: bool [TRACKED], + error_format: ErrorOutputType [UNTRACKED], + + // If `Some`, enable incremental compilation, using the given + // directory to store intermediate results. + incremental: Option [UNTRACKED], + + debugging_opts: DebuggingOptions [TRACKED], + prints: Vec [UNTRACKED], + // Determines which borrow checker(s) to run. This is the parsed, sanitized + // version of `debugging_opts.borrowck`, which is just a plain string. + borrowck_mode: BorrowckMode [UNTRACKED], + cg: CodegenOptions [TRACKED], + externs: Externs [UNTRACKED], + crate_name: Option [TRACKED], + // An optional name to use as the crate for std during std injection, + // written `extern crate name as std`. Defaults to `std`. Used by + // out-of-tree drivers. + alt_std_name: Option [TRACKED], + // Indicates how the compiler should treat unstable features. + unstable_features: UnstableFeatures [TRACKED], + + // Indicates whether this run of the compiler is actually rustdoc. This + // is currently just a hack and will be removed eventually, so please + // try to not rely on this too much. + actually_rustdoc: bool [TRACKED], + + // Specifications of codegen units / ThinLTO which are forced as a + // result of parsing command line options. These are not necessarily + // what rustc was invoked with, but massaged a bit to agree with + // commands like `--emit llvm-ir` which they're often incompatible with + // if we otherwise use the defaults of rustc. + cli_forced_codegen_units: Option [UNTRACKED], + cli_forced_thinlto_off: bool [UNTRACKED], + + // Remap source path prefixes in all output (messages, object files, debug, etc.). + remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], + + edition: Edition [TRACKED], + + // `true` if we're emitting JSON blobs about each artifact produced + // by the compiler. + json_artifact_notifications: bool [TRACKED], + + pretty: Option [UNTRACKED], + } +); + +/// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this +/// macro is to define an interface that can be programmatically used by the option parser +/// to initialize the struct without hardcoding field names all over the place. +/// +/// The goal is to invoke this macro once with the correct fields, and then this macro generates all +/// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of +/// generated code to parse an option into its respective field in the struct. There are a few +/// hand-written parsers for parsing specific types of values in this module. +macro_rules! options { + ($struct_name:ident, $setter_name:ident, $defaultfn:ident, + $buildfn:ident, $prefix:expr, $outputname:expr, + $stat:ident, $mod_desc:ident, $mod_set:ident, + $($opt:ident : $t:ty = ( + $init:expr, + $parse:ident, + [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*], + $desc:expr) + ),* ,) => +( + #[derive(Clone)] + pub struct $struct_name { $(pub $opt: $t),* } + + pub fn $defaultfn() -> $struct_name { + $struct_name { $($opt: $init),* } + } + + pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name + { + let mut op = $defaultfn(); + for option in matches.opt_strs($prefix) { + let mut iter = option.splitn(2, '='); + let key = iter.next().unwrap(); + let value = iter.next(); + let option_to_lookup = key.replace("-", "_"); + let mut found = false; + for &(candidate, setter, opt_type_desc, _) in $stat { + if option_to_lookup != candidate { continue } + if !setter(&mut op, value) { + match (value, opt_type_desc) { + (Some(..), None) => { + early_error(error_format, &format!("{} option `{}` takes no \ + value", $outputname, key)) + } + (None, Some(type_desc)) => { + early_error(error_format, &format!("{0} option `{1}` requires \ + {2} ({3} {1}=)", + $outputname, key, + type_desc, $prefix)) + } + (Some(value), Some(type_desc)) => { + early_error(error_format, &format!("incorrect value `{}` for {} \ + option `{}` - {} was expected", + value, $outputname, + key, type_desc)) + } + (None, None) => panic!() + } + } + found = true; + break; + } + if !found { + early_error(error_format, &format!("unknown {} option: `{}`", + $outputname, key)); + } + } + return op; + } + + impl dep_tracking::DepTrackingHash for $struct_name { + fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { + let mut sub_hashes = BTreeMap::new(); + $({ + hash_option!($opt, + &self.$opt, + &mut sub_hashes, + [$dep_tracking_marker $($dep_warn_val, + $dep_warn_text, + error_format)*]); + })* + dep_tracking::stable_hash(sub_hashes, hasher, error_format); + } + } + + pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool; + pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] = + &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ]; + + #[allow(non_upper_case_globals, dead_code)] + mod $mod_desc { + pub const parse_bool: Option<&str> = None; + pub const parse_opt_bool: Option<&str> = + Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); + pub const parse_string: Option<&str> = Some("a string"); + pub const parse_string_push: Option<&str> = Some("a string"); + pub const parse_pathbuf_push: Option<&str> = Some("a path"); + pub const parse_opt_string: Option<&str> = Some("a string"); + pub const parse_opt_pathbuf: Option<&str> = Some("a path"); + pub const parse_list: Option<&str> = Some("a space-separated list of strings"); + pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings"); + pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings"); + pub const parse_threads: Option<&str> = Some("a number"); + pub const parse_uint: Option<&str> = Some("a number"); + pub const parse_passes: Option<&str> = + Some("a space-separated list of passes, or `all`"); + pub const parse_opt_uint: Option<&str> = + Some("a number"); + pub const parse_panic_strategy: Option<&str> = + Some("either `unwind` or `abort`"); + pub const parse_relro_level: Option<&str> = + Some("one of: `full`, `partial`, or `off`"); + pub const parse_sanitizer: Option<&str> = + Some("one of: `address`, `leak`, `memory` or `thread`"); + pub const parse_sanitizer_list: Option<&str> = + Some("comma separated list of sanitizers"); + pub const parse_sanitizer_memory_track_origins: Option<&str> = None; + pub const parse_linker_flavor: Option<&str> = + Some(::rustc_target::spec::LinkerFlavor::one_of()); + pub const parse_optimization_fuel: Option<&str> = + Some("crate=integer"); + pub const parse_unpretty: Option<&str> = + Some("`string` or `string=string`"); + pub const parse_treat_err_as_bug: Option<&str> = + Some("either no value or a number bigger than 0"); + pub const parse_lto: Option<&str> = + Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \ + `fat`, or omitted"); + pub const parse_linker_plugin_lto: Option<&str> = + Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \ + or the path to the linker plugin"); + pub const parse_switch_with_opt_path: Option<&str> = + Some("an optional path to the profiling data output directory"); + pub const parse_merge_functions: Option<&str> = + Some("one of: `disabled`, `trampolines`, or `aliases`"); + pub const parse_symbol_mangling_version: Option<&str> = + Some("either `legacy` or `v0` (RFC 2603)"); + } + + #[allow(dead_code)] + mod $mod_set { + use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath, + SymbolManglingVersion}; + use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; + use std::path::PathBuf; + use std::str::FromStr; + + $( + pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { + $parse(&mut cg.$opt, v) + } + )* + + fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool { + match v { + Some(..) => false, + None => { *slot = true; true } + } + } + + fn parse_opt_bool(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { + match s { + "n" | "no" | "off" => { + *slot = Some(false); + } + "y" | "yes" | "on" => { + *slot = Some(true); + } + _ => { return false; } + } + + true + }, + None => { *slot = Some(true); true } + } + } + + fn parse_opt_string(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { *slot = Some(s.to_string()); true }, + None => false, + } + } + + fn parse_opt_pathbuf(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { *slot = Some(PathBuf::from(s)); true }, + None => false, + } + } + + fn parse_string(slot: &mut String, v: Option<&str>) -> bool { + match v { + Some(s) => { *slot = s.to_string(); true }, + None => false, + } + } + + fn parse_string_push(slot: &mut Vec, v: Option<&str>) -> bool { + match v { + Some(s) => { slot.push(s.to_string()); true }, + None => false, + } + } + + fn parse_pathbuf_push(slot: &mut Vec, v: Option<&str>) -> bool { + match v { + Some(s) => { slot.push(PathBuf::from(s)); true }, + None => false, + } + } + + fn parse_list(slot: &mut Vec, v: Option<&str>) + -> bool { + match v { + Some(s) => { + slot.extend(s.split_whitespace().map(|s| s.to_string())); + true + }, + None => false, + } + } + + fn parse_opt_list(slot: &mut Option>, v: Option<&str>) + -> bool { + match v { + Some(s) => { + let v = s.split_whitespace().map(|s| s.to_string()).collect(); + *slot = Some(v); + true + }, + None => false, + } + } + + fn parse_opt_comma_list(slot: &mut Option>, v: Option<&str>) + -> bool { + match v { + Some(s) => { + let v = s.split(',').map(|s| s.to_string()).collect(); + *slot = Some(v); + true + }, + None => false, + } + } + + fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(0) => { *slot = ::num_cpus::get(); true }, + Some(i) => { *slot = i; true }, + None => false + } + } + + fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { + match v.and_then(|s| s.parse().ok()) { + Some(i) => { *slot = i; true }, + None => false + } + } + + fn parse_opt_uint(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { *slot = s.parse().ok(); slot.is_some() } + None => { *slot = None; false } + } + } + + fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { + match v { + Some("all") => { + *slot = Passes::All; + true + } + v => { + let mut passes = vec![]; + if parse_list(&mut passes, v) { + *slot = Passes::Some(passes); + true + } else { + false + } + } + } + } + + fn parse_panic_strategy(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some("unwind") => *slot = Some(PanicStrategy::Unwind), + Some("abort") => *slot = Some(PanicStrategy::Abort), + _ => return false + } + true + } + + fn parse_relro_level(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { + match s.parse::() { + Ok(level) => *slot = Some(level), + _ => return false + } + }, + _ => return false + } + true + } + + fn parse_sanitizer(slot: &mut Option, v: Option<&str>) -> bool { + if let Some(Ok(s)) = v.map(str::parse) { + *slot = Some(s); + true + } else { + false + } + } + + fn parse_sanitizer_list(slot: &mut Vec, v: Option<&str>) -> bool { + if let Some(v) = v { + for s in v.split(',').map(str::parse) { + if let Ok(s) = s { + if !slot.contains(&s) { + slot.push(s); + } + } else { + return false; + } + } + true + } else { + false + } + } + + fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool { + match v.map(|s| s.parse()) { + None => { + *slot = 2; + true + } + Some(Ok(i)) if i <= 2 => { + *slot = i; + true + } + _ => { + false + } + } + } + + fn parse_linker_flavor(slote: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavor::from_str) { + Some(lf) => *slote = Some(lf), + _ => return false, + } + true + } + + fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::>(); + if parts.len() != 2 { return false; } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::(); + if fuel.is_err() { return false; } + *slot = Some((crate_name, fuel.unwrap())); + true + } + } + } + + fn parse_unpretty(slot: &mut Option, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) if s.split('=').count() <= 2 => { + *slot = Some(s.to_string()); + true + } + _ => false, + } + } + + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { + match v { + Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } + None => { *slot = Some(1); true } + } + } + + fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + LtoCli::Yes + } else { + LtoCli::No + }; + return true + } + } + + *slot = match v { + None => LtoCli::NoParam, + Some("thin") => LtoCli::Thin, + Some("fat") => LtoCli::Fat, + Some(_) => return false, + }; + true + } + + fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + LinkerPluginLto::LinkerPluginAuto + } else { + LinkerPluginLto::Disabled + }; + return true + } + } + + *slot = match v { + None => LinkerPluginLto::LinkerPluginAuto, + Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)), + }; + true + } + + fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool { + *slot = match v { + None => SwitchWithOptPath::Enabled(None), + Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))), + }; + true + } + + fn parse_merge_functions(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(|s| MergeFunctions::from_str(s).ok()) { + Some(mergefunc) => *slot = Some(mergefunc), + _ => return false, + } + true + } + + fn parse_symbol_mangling_version( + slot: &mut SymbolManglingVersion, + v: Option<&str>, + ) -> bool { + *slot = match v { + Some("legacy") => SymbolManglingVersion::Legacy, + Some("v0") => SymbolManglingVersion::V0, + _ => return false, + }; + true + } + } +) } + +options! {CodegenOptions, CodegenSetter, basic_codegen_options, + build_codegen_options, "C", "codegen", + CG_OPTIONS, cg_type_desc, cgsetters, + ar: Option = (None, parse_opt_string, [UNTRACKED], + "this option is deprecated and does nothing"), + linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], + "system linker to link outputs with"), + link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], + "a single extra argument to append to the linker invocation (can be used several times)"), + link_args: Option> = (None, parse_opt_list, [UNTRACKED], + "extra arguments to append to the linker invocation (space separated)"), + link_dead_code: bool = (false, parse_bool, [UNTRACKED], + "don't let linker strip dead code (turning it on can be used for code coverage)"), + lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED], + "perform LLVM link-time optimizations"), + target_cpu: Option = (None, parse_opt_string, [TRACKED], + "select target processor (`rustc --print target-cpus` for details)"), + target_feature: String = (String::new(), parse_string, [TRACKED], + "target specific attributes. (`rustc --print target-features` for details). \ + This feature is unsafe."), + passes: Vec = (Vec::new(), parse_list, [TRACKED], + "a list of extra LLVM passes to run (space separated)"), + llvm_args: Vec = (Vec::new(), parse_list, [TRACKED], + "a list of arguments to pass to LLVM (space separated)"), + save_temps: bool = (false, parse_bool, [UNTRACKED], + "save all temporary output files during compilation"), + rpath: bool = (false, parse_bool, [UNTRACKED], + "set rpath values in libs/exes"), + overflow_checks: Option = (None, parse_opt_bool, [TRACKED], + "use overflow checks for integer arithmetic"), + no_prepopulate_passes: bool = (false, parse_bool, [TRACKED], + "don't pre-populate the pass manager with a list of passes"), + no_vectorize_loops: bool = (false, parse_bool, [TRACKED], + "don't run the loop vectorization optimization passes"), + no_vectorize_slp: bool = (false, parse_bool, [TRACKED], + "don't run LLVM's SLP vectorization pass"), + soft_float: bool = (false, parse_bool, [TRACKED], + "use soft float ABI (*eabihf targets only)"), + prefer_dynamic: bool = (false, parse_bool, [TRACKED], + "prefer dynamic linking to static linking"), + no_integrated_as: bool = (false, parse_bool, [TRACKED], + "use an external assembler rather than LLVM's integrated one"), + no_redzone: Option = (None, parse_opt_bool, [TRACKED], + "disable the use of the redzone"), + relocation_model: Option = (None, parse_opt_string, [TRACKED], + "choose the relocation model to use (`rustc --print relocation-models` for details)"), + code_model: Option = (None, parse_opt_string, [TRACKED], + "choose the code model to use (`rustc --print code-models` for details)"), + metadata: Vec = (Vec::new(), parse_list, [TRACKED], + "metadata to mangle symbol names with"), + extra_filename: String = (String::new(), parse_string, [UNTRACKED], + "extra data to put in each output filename"), + codegen_units: Option = (None, parse_opt_uint, [UNTRACKED], + "divide crate into N units to optimize in parallel"), + remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED], + "print remarks for these optimization passes (space separated, or \"all\")"), + no_stack_check: bool = (false, parse_bool, [UNTRACKED], + "the `--no-stack-check` flag is deprecated and does nothing"), + debuginfo: Option = (None, parse_opt_uint, [TRACKED], + "debug info emission level, 0 = no debug info, 1 = line tables only, \ + 2 = full debug info with variable and type information"), + opt_level: Option = (None, parse_opt_string, [TRACKED], + "optimize with possible levels 0-3, s, or z"), + force_frame_pointers: Option = (None, parse_opt_bool, [TRACKED], + "force use of the frame pointers"), + debug_assertions: Option = (None, parse_opt_bool, [TRACKED], + "explicitly enable the `cfg(debug_assertions)` directive"), + inline_threshold: Option = (None, parse_opt_uint, [TRACKED], + "set the threshold for inlining a function (default: 225)"), + panic: Option = (None, parse_panic_strategy, + [TRACKED], "panic strategy to compile crate with"), + incremental: Option = (None, parse_opt_string, [UNTRACKED], + "enable incremental compilation"), + default_linker_libraries: Option = (None, parse_opt_bool, [UNTRACKED], + "allow the linker to link its default libraries"), + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + "linker flavor"), + linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, + parse_linker_plugin_lto, [TRACKED], + "generate build artifacts that are compatible with linker-based LTO."), + profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled, + parse_switch_with_opt_path, [TRACKED], + "compile the program with profiling instrumentation"), + profile_use: Option = (None, parse_opt_pathbuf, [TRACKED], + "use the given `.profdata` file for profile-guided optimization"), +} + +options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, + build_debugging_options, "Z", "debugging", + DB_OPTIONS, db_type_desc, dbsetters, + codegen_backend: Option = (None, parse_opt_string, [TRACKED], + "the backend to use"), + verbose: bool = (false, parse_bool, [UNTRACKED], + "in general, enable more debug printouts"), + span_free_formats: bool = (false, parse_bool, [UNTRACKED], + "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path + identify_regions: bool = (false, parse_bool, [UNTRACKED], + "make unnamed regions display as '# (where # is some non-ident unique id)"), + borrowck: Option = (None, parse_opt_string, [UNTRACKED], + "select which borrowck is used (`mir` or `migrate`)"), + time_passes: bool = (false, parse_bool, [UNTRACKED], + "measure time of each rustc pass"), + time: bool = (false, parse_bool, [UNTRACKED], + "measure time of rustc processes"), + time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], + "measure time of each LLVM pass"), + input_stats: bool = (false, parse_bool, [UNTRACKED], + "gather statistics about the input"), + asm_comments: bool = (false, parse_bool, [TRACKED], + "generate comments into the assembly (may change behavior)"), + verify_llvm_ir: bool = (false, parse_bool, [TRACKED], + "verify LLVM IR"), + borrowck_stats: bool = (false, parse_bool, [UNTRACKED], + "gather borrowck statistics"), + no_landing_pads: bool = (false, parse_bool, [TRACKED], + "omit landing pads for unwinding"), + fewer_names: bool = (false, parse_bool, [TRACKED], + "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"), + meta_stats: bool = (false, parse_bool, [UNTRACKED], + "gather metadata statistics"), + print_link_args: bool = (false, parse_bool, [UNTRACKED], + "print the arguments passed to the linker"), + print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], + "prints the LLVM optimization passes being run"), + ast_json: bool = (false, parse_bool, [UNTRACKED], + "print the AST as JSON and halt"), + // We default to 1 here since we want to behave like + // a sequential compiler for now. This'll likely be adjusted + // in the future. Note that -Zthreads=0 is the way to get + // the num_cpus behavior. + threads: usize = (1, parse_threads, [UNTRACKED], + "use a thread pool with N threads"), + ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED], + "print the pre-expansion AST as JSON and halt"), + ls: bool = (false, parse_bool, [UNTRACKED], + "list the symbols defined by a library crate"), + save_analysis: bool = (false, parse_bool, [UNTRACKED], + "write syntax and type analysis (in JSON format) information, in \ + addition to normal output"), + print_region_graph: bool = (false, parse_bool, [UNTRACKED], + "prints region inference graph. \ + Use with RUST_REGION_GRAPH=help for more info"), + parse_only: bool = (false, parse_bool, [UNTRACKED], + "parse only; do not compile, assemble, or link"), + dual_proc_macros: bool = (false, parse_bool, [TRACKED], + "load proc macros for both target and host, but only link to the target"), + no_codegen: bool = (false, parse_bool, [TRACKED], + "run all passes except codegen; no output"), + treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], + "treat error number `val` that occurs as bug"), + report_delayed_bugs: bool = (false, parse_bool, [TRACKED], + "immediately print bugs registered with `delay_span_bug`"), + external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], + "show macro backtraces even for non-local macros"), + teach: bool = (false, parse_bool, [TRACKED], + "show extended diagnostic help"), + terminal_width: Option = (None, parse_opt_uint, [UNTRACKED], + "set the current terminal width"), + panic_abort_tests: bool = (false, parse_bool, [TRACKED], + "support compiling tests with panic=abort"), + continue_parse_after_error: bool = (false, parse_bool, [TRACKED], + "attempt to recover from parse errors (experimental)"), + dep_tasks: bool = (false, parse_bool, [UNTRACKED], + "print tasks that execute and the color their dep node gets (requires debug build)"), + incremental: Option = (None, parse_opt_string, [UNTRACKED], + "enable incremental compilation (experimental)"), + incremental_queries: bool = (true, parse_bool, [UNTRACKED], + "enable incremental compilation support for queries (experimental)"), + incremental_info: bool = (false, parse_bool, [UNTRACKED], + "print high-level information about incremental reuse (or the lack thereof)"), + incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED], + "dump hash information in textual format to stdout"), + incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], + "verify incr. comp. hashes of green query instances"), + incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED], + "ignore spans during ICH computation -- used for testing"), + instrument_mcount: bool = (false, parse_bool, [TRACKED], + "insert function instrument code for mcount-based tracing"), + dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], + "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"), + query_dep_graph: bool = (false, parse_bool, [UNTRACKED], + "enable queries of the dependency graph for regression testing"), + no_analysis: bool = (false, parse_bool, [UNTRACKED], + "parse and expand the source, but run no analysis"), + unstable_options: bool = (false, parse_bool, [UNTRACKED], + "adds unstable command line options to rustc interface"), + force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], + "force overflow checks on or off"), + trace_macros: bool = (false, parse_bool, [UNTRACKED], + "for every macro invocation, print its name and arguments"), + debug_macros: bool = (false, parse_bool, [TRACKED], + "emit line numbers debug info inside macros"), + generate_arange_section: bool = (true, parse_bool, [TRACKED], + "generate DWARF address ranges for faster lookups"), + keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], + "don't clear the hygiene data after analysis"), + keep_ast: bool = (false, parse_bool, [UNTRACKED], + "keep the AST after lowering it to HIR"), + show_span: Option = (None, parse_opt_string, [TRACKED], + "show spans for compiler debugging (expr|pat|ty)"), + print_type_sizes: bool = (false, parse_bool, [UNTRACKED], + "print layout information for each type encountered"), + print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], + "print the result of the monomorphization collection pass"), + mir_opt_level: usize = (1, parse_uint, [TRACKED], + "set the MIR optimization level (0-3, default: 1)"), + mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], + "emit noalias metadata for mutable references (default: no)"), + dump_mir: Option = (None, parse_opt_string, [UNTRACKED], + "dump MIR state to file. + `val` is used to select which passes and functions to dump. For example: + `all` matches all passes and functions, + `foo` matches all passes for functions whose name contains 'foo', + `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo', + `foo | bar` all passes for function names containing 'foo' or 'bar'."), + + dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED], + "the directory the MIR is dumped into"), + dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], + "in addition to `.mir` files, create graphviz `.dot` files"), + dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], + "if set, exclude the pass number when dumping MIR (used in tests)"), + mir_emit_retag: bool = (false, parse_bool, [TRACKED], + "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"), + perf_stats: bool = (false, parse_bool, [UNTRACKED], + "print some performance-related statistics"), + query_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about the query system"), + hir_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about AST and HIR"), + always_encode_mir: bool = (false, parse_bool, [TRACKED], + "encode MIR of all functions into the crate metadata"), + json_rendered: Option = (None, parse_opt_string, [UNTRACKED], + "describes how to render the `rendered` field of json diagnostics"), + unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], + "take the breaks off const evaluation. NOTE: this is unsound"), + osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], + "pass `-install_name @rpath/...` to the macOS linker"), + sanitizer: Option = (None, parse_sanitizer, [TRACKED], + "use a sanitizer"), + sanitizer_recover: Vec = (vec![], parse_sanitizer_list, [TRACKED], + "Enable recovery for selected sanitizers"), + sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED], + "Enable origins tracking in MemorySanitizer"), + fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], + "set the optimization fuel quota for a crate"), + print_fuel: Option = (None, parse_opt_string, [TRACKED], + "make rustc print the total optimization fuel used by a crate"), + force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], + "force all crates to be `rustc_private` unstable"), + pre_link_arg: Vec = (vec![], parse_string_push, [UNTRACKED], + "a single extra argument to prepend the linker invocation (can be used several times)"), + pre_link_args: Option> = (None, parse_opt_list, [UNTRACKED], + "extra arguments to prepend to the linker invocation (space separated)"), + profile: bool = (false, parse_bool, [TRACKED], + "insert profiling code"), + disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED], + "Disable the instrumentation pre-inliner, useful for profiling / PGO."), + relro_level: Option = (None, parse_relro_level, [TRACKED], + "choose which RELRO level to use"), + nll_facts: bool = (false, parse_bool, [UNTRACKED], + "dump facts from NLL analysis into side files"), + nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED], + "in match codegen, do not include FakeRead statements (used by mir-borrowck)"), + dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], + "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."), + polonius: bool = (false, parse_bool, [UNTRACKED], + "enable polonius-based borrow-checker"), + codegen_time_graph: bool = (false, parse_bool, [UNTRACKED], + "generate a graphical HTML report of time spent in codegen and LLVM"), + thinlto: Option = (None, parse_opt_bool, [TRACKED], + "enable ThinLTO when possible"), + inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], + "control whether `#[inline]` functions are in all CGUs"), + tls_model: Option = (None, parse_opt_string, [TRACKED], + "choose the TLS model to use (`rustc --print tls-models` for details)"), + saturating_float_casts: bool = (false, parse_bool, [TRACKED], + "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ + the max/min integer respectively, and NaN is mapped to 0"), + human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], + "generate human-readable, predictable names for codegen units"), + dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], + "in dep-info output, omit targets for tracking dependencies of the dep-info files \ + themselves"), + unpretty: Option = (None, parse_unpretty, [UNTRACKED], + "present the input source, unstable (and less-pretty) variants; + valid types are any of the types for `--pretty`, as well as: + `expanded`, `expanded,identified`, + `expanded,hygiene` (with internal representations), + `everybody_loops` (all function bodies replaced with `loop {}`), + `hir` (the HIR), `hir,identified`, + `hir,typed` (HIR with types for each node), + `hir-tree` (dump the raw HIR), + `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), + run_dsymutil: Option = (None, parse_opt_bool, [TRACKED], + "run `dsymutil` and delete intermediate object files"), + ui_testing: bool = (false, parse_bool, [UNTRACKED], + "format compiler diagnostics in a way that's better suitable for UI testing"), + embed_bitcode: bool = (false, parse_bool, [TRACKED], + "embed LLVM bitcode in object files"), + strip_debuginfo_if_disabled: Option = (None, parse_opt_bool, [TRACKED], + "tell the linker to strip debuginfo when building without debuginfo enabled."), + share_generics: Option = (None, parse_opt_bool, [TRACKED], + "make the current crate share its generic instantiations"), + chalk: bool = (false, parse_bool, [TRACKED], + "enable the experimental Chalk-based trait solving engine"), + no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED], + "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"), + no_leak_check: bool = (false, parse_bool, [UNTRACKED], + "disables the 'leak check' for subtyping; unsound, but useful for tests"), + no_interleave_lints: bool = (false, parse_bool, [UNTRACKED], + "don't interleave execution of lints; allows benchmarking individual lints"), + crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], + "inject the given attribute in the crate"), + self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, + parse_switch_with_opt_path, [UNTRACKED], + "run the self profiler and output the raw event data"), + self_profile_events: Option> = (None, parse_opt_comma_list, [UNTRACKED], + "specifies which kinds of events get recorded by the self profiler"), + emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], + "emits a section containing stack size metadata"), + plt: Option = (None, parse_opt_bool, [TRACKED], + "whether to use the PLT when calling into shared libraries; + only has effect for PIC code on systems with ELF binaries + (default: PLT is disabled if full relro is enabled)"), + merge_functions: Option = (None, parse_merge_functions, [TRACKED], + "control the operation of the MergeFunctions LLVM pass, taking + the same values as the target option of the same name"), + allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], + "only allow the listed language features to be enabled in code (space separated)"), + symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy, + parse_symbol_mangling_version, [TRACKED], + "which mangling version to use for symbol names"), + binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], + "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"), + insert_sideeffect: bool = (false, parse_bool, [TRACKED], + "fix undefined behavior when a thread doesn't eventually make progress \ + (such as entering an empty infinite loop) by inserting llvm.sideeffect"), +}