diff --git a/compiler/rustc_interface/locales/en-US.ftl b/compiler/rustc_interface/locales/en-US.ftl index a7bc0e7af1fe9..da58492ccf27c 100644 --- a/compiler/rustc_interface/locales/en-US.ftl +++ b/compiler/rustc_interface/locales/en-US.ftl @@ -11,10 +11,6 @@ interface_mixed_bin_crate = interface_mixed_proc_macro_crate = cannot mix `proc-macro` crate type with others -interface_proc_macro_doc_without_arg = - Trying to document proc macro crate without passing '--crate-type proc-macro to rustdoc - .warn = The generated documentation may be incorrect - interface_error_writing_dependencies = error writing dependencies to `{$path}`: {$error} diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index 29543fe2f932c..0eedee250269e 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -31,10 +31,6 @@ pub struct MixedBinCrate; #[diag(interface_mixed_proc_macro_crate)] pub struct MixedProcMacroCrate; -#[derive(Diagnostic)] -#[diag(interface_proc_macro_doc_without_arg)] -pub struct ProcMacroDocWithoutArg; - #[derive(Diagnostic)] #[diag(interface_error_writing_dependencies)] pub struct ErrorWritingDependencies<'a> { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aa59654099a68..81c1d665ef072 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -287,28 +287,18 @@ fn configure_and_expand(mut krate: ast::Crate, resolver: &mut Resolver<'_, '_>) sess.emit_warning(errors::ProcMacroCratePanicAbort); } - // For backwards compatibility, we don't try to run proc macro injection - // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being - // specified. This should only affect users who manually invoke 'rustdoc', as - // 'cargo doc' will automatically pass the proper '--crate-type' flags. - // However, we do emit a warning, to let such users know that they should - // start passing '--crate-type proc-macro' - if has_proc_macro_decls && sess.opts.actually_rustdoc && !is_proc_macro_crate { - sess.emit_warning(errors::ProcMacroDocWithoutArg); - } else { - krate = sess.time("maybe_create_a_macro_crate", || { - let is_test_crate = sess.opts.test; - rustc_builtin_macros::proc_macro_harness::inject( - sess, - resolver, - krate, - is_proc_macro_crate, - has_proc_macro_decls, - is_test_crate, - sess.diagnostic(), - ) - }); - } + krate = sess.time("maybe_create_a_macro_crate", || { + let is_test_crate = sess.opts.test; + rustc_builtin_macros::proc_macro_harness::inject( + sess, + resolver, + krate, + is_proc_macro_crate, + has_proc_macro_decls, + is_test_crate, + sess.diagnostic(), + ) + }); // Done with macro expansion! diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 71a72036994d2..18d84a7023aa1 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -756,6 +756,7 @@ fn test_unstable_options_tracking_hash() { tracked!(instrument_coverage, Some(InstrumentCoverage::All)); tracked!(instrument_mcount, true); tracked!(instrument_xray, Some(InstrumentXRay::default())); + tracked!(link_directives, false); tracked!(link_only, true); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9d8ad9d9ed9f6..46ec1a2dca1f7 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4103,3 +4103,33 @@ declare_lint! { }; report_in_external_macro } + +declare_lint! { + /// The `invalid_macro_export_arguments` lint detects cases where `#[macro_export]` is being used with invalid arguments. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(invalid_macro_export_arguments)] + /// + /// #[macro_export(invalid_parameter)] + /// macro_rules! myMacro { + /// () => { + /// // [...] + /// } + /// } + /// + /// #[macro_export(too, many, items)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The only valid argument is `#[macro_export(local_inner_macros)]` or no argument (`#[macro_export]`). + /// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`. + /// + pub INVALID_MACRO_EXPORT_ARGUMENTS, + Warn, + "\"invalid_parameter\" isn't a valid argument for `#[macro_export]`", +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 5a4d358e5dd62..d6f68b2e14055 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -103,8 +103,13 @@ impl<'tcx> Collector<'tcx> { } // Process all of the #[link(..)]-style arguments - let sess = &self.tcx.sess; + let sess = self.tcx.sess; let features = self.tcx.features(); + + if !sess.opts.unstable_opts.link_directives { + return; + } + for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) { let Some(items) = m.meta_item_list() else { continue; diff --git a/compiler/rustc_passes/locales/en-US.ftl b/compiler/rustc_passes/locales/en-US.ftl index 8fe8472b21630..0ed29ce0d4795 100644 --- a/compiler/rustc_passes/locales/en-US.ftl +++ b/compiler/rustc_passes/locales/en-US.ftl @@ -745,3 +745,7 @@ passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}" passes_proc_macro_unsafe = proc macro functions may not be `unsafe` passes_skipping_const_checks = skipping const checks + +passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument + +passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bb09dcbdd6980..5ef3e13eff801 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -23,7 +23,8 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{ParamEnv, TyCtxt}; use rustc_session::lint::builtin::{ - CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, + CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, + UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; @@ -2102,7 +2103,33 @@ impl CheckAttrVisitor<'_> { fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) { if target != Target::MacroDef { - self.tcx.emit_spanned_lint(UNUSED_ATTRIBUTES, hir_id, attr.span, errors::MacroExport); + self.tcx.emit_spanned_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr.span, + errors::MacroExport::Normal, + ); + } else if let Some(meta_item_list) = attr.meta_item_list() && + !meta_item_list.is_empty() { + if meta_item_list.len() > 1 { + self.tcx.emit_spanned_lint( + INVALID_MACRO_EXPORT_ARGUMENTS, + hir_id, + attr.span, + errors::MacroExport::TooManyItems, + ); + } else { + if meta_item_list[0].name_or_empty() != sym::local_inner_macros { + self.tcx.emit_spanned_lint( + INVALID_MACRO_EXPORT_ARGUMENTS, + hir_id, + meta_item_list[0].span(), + errors::MacroExport::UnknownItem { + name: meta_item_list[0].name_or_empty(), + }, + ); + } + } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 82fc3eeff94ab..2c0d21b479848 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -641,8 +641,16 @@ pub struct MacroUse { } #[derive(LintDiagnostic)] -#[diag(passes_macro_export)] -pub struct MacroExport; +pub enum MacroExport { + #[diag(passes_macro_export)] + Normal, + + #[diag(passes_invalid_macro_export_arguments)] + UnknownItem { name: Symbol }, + + #[diag(passes_invalid_macro_export_arguments_too_many_items)] + TooManyItems, +} #[derive(LintDiagnostic)] #[diag(passes_plugin_registrar)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1f3eb8d4832fe..4beac931632be 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1489,6 +1489,8 @@ options! { "keep hygiene data after analysis (default: no)"), layout_seed: Option = (None, parse_opt_number, [TRACKED], "seed layout randomization"), + link_directives: bool = (true, parse_bool, [TRACKED], + "honor #[link] directives in the compiled crate (default: yes)"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 6172a9539f64d..dec9f8016b0c1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -99,6 +99,15 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable> + Copy + Eq { requirements: impl IntoIterator>>, ) -> QueryResult<'tcx>; + // Consider a clause specifically for a `dyn Trait` self type. This requires + // additionally checking all of the supertraits and object bounds to hold, + // since they're not implied by the well-formedness of the object type. + fn consider_object_bound_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx>; + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -455,7 +464,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) { - match G::consider_implied_clause(self, goal, assumption.predicate, []) { + match G::consider_object_bound_candidate(self, goal, assumption.predicate) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index d4fdd54573751..88fd8bb8bd095 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -128,6 +128,51 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { } } + fn consider_object_bound_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() + && poly_projection_pred.projection_def_id() == goal.predicate.def_id() + { + ecx.probe(|ecx| { + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(poly_projection_pred); + let mut nested_goals = ecx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + + let tcx = ecx.tcx(); + let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { + bug!("expected object type in `consider_object_bound_candidate`"); + }; + nested_goals.extend( + structural_traits::predicates_for_object_candidate( + ecx, + goal.param_env, + goal.predicate.projection_ty.trait_ref(tcx), + bounds, + ) + .into_iter() + .map(|pred| goal.with(tcx, pred)), + ); + + let subst_certainty = ecx.evaluate_all(nested_goals)?; + + ecx.eq_term_and_make_canonical_response( + goal, + subst_certainty, + assumption_projection_pred.term, + ) + }) + } else { + Err(NoSolution) + } + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 68bb7c877e3d9..5c499c36e9bf4 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -86,6 +86,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } } + fn consider_object_bound_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() + && poly_trait_pred.def_id() == goal.predicate.def_id() + { + // FIXME: Constness and polarity + ecx.probe(|ecx| { + let assumption_trait_pred = + ecx.instantiate_binder_with_infer(poly_trait_pred); + let mut nested_goals = ecx.eq( + goal.param_env, + goal.predicate.trait_ref, + assumption_trait_pred.trait_ref, + )?; + + let tcx = ecx.tcx(); + let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { + bug!("expected object type in `consider_object_bound_candidate`"); + }; + nested_goals.extend( + structural_traits::predicates_for_object_candidate( + ecx, + goal.param_env, + goal.predicate.trait_ref, + bounds, + ) + .into_iter() + .map(|pred| goal.with(tcx, pred)), + ); + + ecx.evaluate_all_and_make_canonical_response(nested_goals) + }) + } else { + Err(NoSolution) + } + } + fn consider_auto_trait_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs index 3a887f54587f4..f7d1b4be74bf8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -1,6 +1,7 @@ -use rustc_hir::{Movability, Mutability}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::{def_id::DefId, Movability, Mutability}; use rustc_infer::traits::query::NoSolution; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::solve::EvalCtxt; @@ -231,3 +232,112 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( } } } + +/// Assemble a list of predicates that would be present on a theoretical +/// user impl for an object type. These predicates must be checked any time +/// we assemble a built-in object candidate for an object type, since they +/// are not implied by the well-formedness of the type. +/// +/// For example, given the following traits: +/// +/// ```rust,ignore (theoretical code) +/// trait Foo: Baz { +/// type Bar: Copy; +/// } +/// +/// trait Baz {} +/// ``` +/// +/// For the dyn type `dyn Foo`, we can imagine there being a +/// pair of theoretical impls: +/// +/// ```rust,ignore (theoretical code) +/// impl Foo for dyn Foo +/// where +/// Self: Baz, +/// ::Bar: Copy, +/// { +/// type Bar = Ty; +/// } +/// +/// impl Baz for dyn Foo {} +/// ``` +/// +/// However, in order to make such impls well-formed, we need to do an +/// additional step of eagerly folding the associated types in the where +/// clauses of the impl. In this example, that means replacing +/// `::Bar` with `Ty` in the first impl. +pub(crate) fn predicates_for_object_candidate<'tcx>( + ecx: &EvalCtxt<'_, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + object_bound: &'tcx ty::List>, +) -> Vec> { + let tcx = ecx.tcx(); + let mut requirements = vec![]; + requirements.extend( + tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.substs).predicates, + ); + for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { + // FIXME(associated_const_equality): Also add associated consts to + // the requirements here. + if item.kind == ty::AssocKind::Type { + requirements.extend(tcx.item_bounds(item.def_id).subst(tcx, trait_ref.substs)); + } + } + + let mut replace_projection_with = FxHashMap::default(); + for bound in object_bound { + if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { + let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); + let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); + assert_eq!( + old_ty, + None, + "{} has two substitutions: {} and {}", + proj.projection_ty, + proj.term, + old_ty.unwrap() + ); + } + } + + requirements.fold_with(&mut ReplaceProjectionWith { + ecx, + param_env, + mapping: replace_projection_with, + }) +} + +struct ReplaceProjectionWith<'a, 'tcx> { + ecx: &'a EvalCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + mapping: FxHashMap>, +} + +impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.ecx.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() + && let Some(replacement) = self.mapping.get(&alias_ty.def_id) + { + // We may have a case where our object type's projection bound is higher-ranked, + // but the where clauses we instantiated are not. We can solve this by instantiating + // the binder at the usage site. + let proj = self.ecx.instantiate_binder_with_infer(*replacement); + // FIXME: Technically this folder could be fallible? + let nested = self + .ecx + .eq(self.param_env, alias_ty, proj.projection_ty) + .expect("expected to be able to unify goal projection with dyn's projection"); + // FIXME: Technically we could register these too.. + assert!(nested.is_empty(), "did not expect unification to have any nested goals"); + proj.term.ty().unwrap() + } else { + ty.super_fold_with(self) + } + } +} diff --git a/config.toml.example b/config.toml.example index df4478bb0cb85..69eb228a2d5a0 100644 --- a/config.toml.example +++ b/config.toml.example @@ -666,6 +666,9 @@ changelog-seen = 2 # LTO entirely. #lto = "thin-local" +# Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std` +#validate-mir-opts = 3 + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 952c70cec1c05..b33fc02f49c24 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -792,7 +792,7 @@ impl<'a> Builder<'a> { run::CollectLicenseMetadata, run::GenerateCopyright, ), - Kind::Setup => describe!(setup::Profile), + Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), // special-cased in Build::build() Kind::Format => vec![], @@ -1915,6 +1915,13 @@ impl<'a> Builder<'a> { } } + if matches!(mode, Mode::Std) { + if let Some(mir_opt_level) = self.config.rust_validate_mir_opts { + rustflags.arg("-Zvalidate-mir"); + rustflags.arg(&format!("-Zmir-opt-level={}", mir_opt_level)); + } + } + Cargo { command: cargo, rustflags, rustdocflags, allow_features } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 56f96734bbbc7..4a563bc396dc4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -173,6 +173,7 @@ pub struct Config { pub rust_profile_use: Option, pub rust_profile_generate: Option, pub rust_lto: RustcLto, + pub rust_validate_mir_opts: Option, pub llvm_profile_use: Option, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option, @@ -770,6 +771,7 @@ define_config! { // ignored; this is set from an env var set by bootstrap.py download_rustc: Option = "download-rustc", lto: Option = "lto", + validate_mir_opts: Option = "validate-mir-opts", } } @@ -1149,6 +1151,7 @@ impl Config { .as_deref() .map(|value| RustcLto::from_str(value).unwrap()) .unwrap_or_default(); + config.rust_validate_mir_opts = rust.validate_mir_opts; } else { config.rust_profile_use = flags.rust_profile_use; config.rust_profile_generate = flags.rust_profile_generate; diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 0af329e7007ac..04e798e3949d9 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -379,8 +379,14 @@ def set(key, value): sections[None] = [] section_order = [None] targets = {} +top_level_keys = [] for line in open(rust_dir + '/config.toml.example').read().split("\n"): + if cur_section == None: + if line.count('=') == 1: + top_level_key = line.split('=')[0] + top_level_key = top_level_key.strip(' #') + top_level_keys.append(top_level_key) if line.startswith('['): cur_section = line[1:-1] if cur_section.startswith('target'): @@ -459,12 +465,22 @@ def configure_section(lines, config): raise RuntimeError("failed to find config line for {}".format(key)) -for section_key in config: - section_config = config[section_key] - if section_key not in sections: - raise RuntimeError("config key {} not in sections".format(section_key)) +def configure_top_level_key(lines, top_level_key, value): + for i, line in enumerate(lines): + if line.startswith('#' + top_level_key + ' = ') or line.startswith(top_level_key + ' = '): + lines[i] = "{} = {}".format(top_level_key, value) + return - if section_key == 'target': + raise RuntimeError("failed to find config line for {}".format(top_level_key)) + + +for section_key, section_config in config.items(): + if section_key not in sections and section_key not in top_level_keys: + raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key)) + if section_key in top_level_keys: + configure_top_level_key(sections[None], section_key, section_config) + + elif section_key == 'target': for target in section_config: configure_section(targets[target], section_config[target]) else: diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index f07e710a9e6b7..9d1504c34e817 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -554,7 +554,8 @@ Arguments: Kind::Setup => { subcommand_help.push_str(&format!( "\n -x.py setup creates a `config.toml` which changes the defaults for x.py itself. +x.py setup creates a `config.toml` which changes the defaults for x.py itself, +as well as setting up a git pre-push hook, VS code config and toolchain link. Arguments: This subcommand accepts a 'profile' to use for builds. For example: @@ -564,7 +565,13 @@ Arguments: The profile is optional and you will be prompted interactively if it is not given. The following profiles are available: -{}", +{} + + To only set up the git hook, VS code or toolchain link, you may use + ./x.py setup hook + ./x.py setup vscode + ./x.py setup link +", Profile::all_for_help(" ").trim_end() )); } @@ -638,7 +645,7 @@ Arguments: } Kind::Setup => { let profile = if paths.len() > 1 { - eprintln!("\nerror: At most one profile can be passed to setup\n"); + eprintln!("\nerror: At most one option can be passed to setup\n"); usage(1, &opts, verbose, &subcommand_help) } else if let Some(path) = paths.pop() { let profile_string = t!(path.into_os_string().into_string().map_err( diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index a027139df2397..4480bce99d799 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -21,6 +21,7 @@ pub enum Profile { Library, Tools, User, + None, } /// A list of historical hashes of `src/etc/vscode_settings.json`. @@ -41,7 +42,7 @@ impl Profile { pub fn all() -> impl Iterator { use Profile::*; // N.B. these are ordered by how they are displayed, not alphabetically - [Library, Compiler, Codegen, Tools, User].iter().copied() + [Library, Compiler, Codegen, Tools, User, None].iter().copied() } pub fn purpose(&self) -> String { @@ -52,6 +53,7 @@ impl Profile { Codegen => "Contribute to the compiler, and also modify LLVM or codegen", Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)", User => "Install Rust from source", + None => "Do not modify `config.toml`" } .to_string() } @@ -71,6 +73,7 @@ impl Profile { Profile::Library => "library", Profile::Tools => "tools", Profile::User => "user", + Profile::None => "none", } } } @@ -87,6 +90,7 @@ impl FromStr for Profile { "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { Ok(Profile::Tools) } + "none" => Ok(Profile::None), _ => Err(format!("unknown profile: '{}'", s)), } } @@ -144,17 +148,8 @@ impl Step for Profile { } pub fn setup(config: &Config, profile: Profile) { - let stage_path = - ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string()); - - if !rustup_installed() && profile != Profile::User { - eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); - } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() { - attempt_toolchain_link(&stage_path[..]); - } - - let suggestions = match profile { - Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..], + let suggestions: &[&str] = match profile { + Profile::Codegen | Profile::Compiler | Profile::None => &["check", "build", "test"], Profile::Tools => &[ "check", "build", @@ -167,11 +162,6 @@ pub fn setup(config: &Config, profile: Profile) { Profile::User => &["dist", "build"], }; - if !config.dry_run() { - t!(install_git_hook_maybe(&config)); - t!(create_vscode_settings_maybe(&config)); - } - println!(); println!("To get started, try one of the following commands:"); @@ -190,6 +180,9 @@ pub fn setup(config: &Config, profile: Profile) { } fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { + if profile == Profile::None { + return; + } if path.exists() { eprintln!(); eprintln!( @@ -217,6 +210,41 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { println!("`x.py` will now use the configuration at {}", include_path.display()); } +/// Creates a toolchain link for stage1 using `rustup` +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct Link; +impl Step for Link { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("link") + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "link" { + run.builder.ensure(Link); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + let stage_path = + ["build", config.build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string()); + + if !rustup_installed() { + eprintln!("`rustup` is not installed; cannot link `stage1` toolchain"); + } else if stage_dir_exists(&stage_path[..]) && !config.dry_run() { + attempt_toolchain_link(&stage_path[..]); + } + } +} + fn rustup_installed() -> bool { Command::new("rustup") .arg("--version") @@ -394,6 +422,35 @@ fn prompt_user(prompt: &str) -> io::Result> { } } +/// Installs `src/etc/pre-push.sh` as a Git hook +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct Hook; + +impl Step for Hook { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("hook") + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "hook" { + run.builder.ensure(Hook); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + t!(install_git_hook_maybe(&config)); + } +} + // install a git hook to automatically run tidy, if they want fn install_git_hook_maybe(config: &Config) -> io::Result<()> { let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| { @@ -432,6 +489,35 @@ undesirable, simply delete the `pre-push` file from .git/hooks." Ok(()) } +/// Sets up or displays `src/etc/vscode_settings.json` +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct Vscode; + +impl Step for Vscode { + type Output = (); + const DEFAULT: bool = true; + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("vscode") + } + fn make_run(run: RunConfig<'_>) { + if run.builder.config.dry_run() { + return; + } + if let [cmd] = &run.paths[..] { + if cmd.assert_single_path().path.as_path().as_os_str() == "vscode" { + run.builder.ensure(Vscode); + } + } + } + fn run(self, builder: &Builder<'_>) -> Self::Output { + let config = &builder.config; + if config.dry_run() { + return; + } + t!(create_vscode_settings_maybe(&config)); + } +} + /// Create a `.vscode/settings.json` file for rustc development, or just print it fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 4cc5d9f8a0daf..98bd90210d615 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -23,6 +23,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}" +ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3" + # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. RUN npm install es-check@6.1.1 eslint@8.6.0 -g @@ -38,7 +40,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ - python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu --all-targets && \ + python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ diff --git a/tests/rustdoc-ui/proc_macro_bug.rs b/tests/rustdoc-ui/proc_macro_bug.rs new file mode 100644 index 0000000000000..e384e4863adb9 --- /dev/null +++ b/tests/rustdoc-ui/proc_macro_bug.rs @@ -0,0 +1,12 @@ +// regression test for failing to pass `--crate-type proc-macro` to rustdoc +// when documenting a proc macro crate https://github.com/rust-lang/rust/pull/107291 + +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_derive(DeriveA)] +//~^ ERROR the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type +pub fn a_derive(input: TokenStream) -> TokenStream { + input +} diff --git a/tests/rustdoc-ui/proc_macro_bug.stderr b/tests/rustdoc-ui/proc_macro_bug.stderr new file mode 100644 index 0000000000000..5b048097c4964 --- /dev/null +++ b/tests/rustdoc-ui/proc_macro_bug.stderr @@ -0,0 +1,8 @@ +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc_macro_bug.rs:8:1 + | +LL | #[proc_macro_derive(DeriveA)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 58b2f92d15040..6aa9785f44e33 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -81,6 +81,7 @@ Multiple options can be combined with commas. -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no) -Z layout-seed=val -- seed layout randomization + -Z link-directives=val -- honor #[link] directives in the compiled crate (default: yes) -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes) -Z link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no) -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs new file mode 100644 index 0000000000000..85d009f11a6f3 --- /dev/null +++ b/tests/ui/attributes/invalid_macro_export_argument.rs @@ -0,0 +1,26 @@ +// check-pass +#[macro_export(hello, world)] //~ WARN `#[macro_export]` can only take 1 or 0 arguments +macro_rules! a { + () => () +} + +#[macro_export(not_local_inner_macros)] //~ WARN `not_local_inner_macros` isn't a valid `#[macro_export]` argument +macro_rules! b { + () => () +} + +#[macro_export] +macro_rules! c { + () => () +} +#[macro_export(local_inner_macros)] +macro_rules! d { + () => () +} + +#[macro_export()] +macro_rules! e { + () => () +} + +fn main() {} diff --git a/tests/ui/attributes/invalid_macro_export_argument.stderr b/tests/ui/attributes/invalid_macro_export_argument.stderr new file mode 100644 index 0000000000000..a4e17642c2aac --- /dev/null +++ b/tests/ui/attributes/invalid_macro_export_argument.stderr @@ -0,0 +1,16 @@ +warning: `#[macro_export]` can only take 1 or 0 arguments + --> $DIR/invalid_macro_export_argument.rs:2:1 + | +LL | #[macro_export(hello, world)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(invalid_macro_export_arguments)]` on by default + +warning: `not_local_inner_macros` isn't a valid `#[macro_export]` argument + --> $DIR/invalid_macro_export_argument.rs:7:16 + | +LL | #[macro_export(not_local_inner_macros)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs b/tests/ui/issues/issue-70093/issue-70093-link-directives.rs new file mode 100644 index 0000000000000..83f9b16c4086a --- /dev/null +++ b/tests/ui/issues/issue-70093/issue-70093-link-directives.rs @@ -0,0 +1,10 @@ +// run-pass +// compile-flags: -Zlink-directives=no +// ignore-windows - this will probably only work on unixish systems +// ignore-fuchsia - missing __libc_start_main for some reason (#84733) +// ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling + +#[link(name = "some-random-non-existent-library", kind = "static")] +extern "C" {} + +fn main() {} diff --git a/tests/ui/issues/issue-70093.rs b/tests/ui/issues/issue-70093/issue-70093.rs similarity index 100% rename from tests/ui/issues/issue-70093.rs rename to tests/ui/issues/issue-70093/issue-70093.rs diff --git a/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs new file mode 100644 index 0000000000000..c886aeeda3e46 --- /dev/null +++ b/tests/ui/traits/new-solver/higher-ranked-dyn-bounds.rs @@ -0,0 +1,17 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Trait<'a> { + type Item: for<'b> Trait2<'b>; +} + +trait Trait2<'a> {} +impl Trait2<'_> for () {} + +fn needs_trait(_: Box Trait<'a> + ?Sized>) {} + +fn foo(x: Box Trait<'a, Item = ()>>) { + needs_trait(x); +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/more-object-bound.rs b/tests/ui/traits/new-solver/more-object-bound.rs new file mode 100644 index 0000000000000..712759ef0e612 --- /dev/null +++ b/tests/ui/traits/new-solver/more-object-bound.rs @@ -0,0 +1,27 @@ +// compile-flags: -Ztrait-solver=next +// From #80800 + +trait SuperTrait { + type A; + type B; +} + +trait Trait: SuperTrait::B> {} + +fn transmute(x: A) -> B { + foo::>(x) + //~^ ERROR type annotations needed: cannot satisfy `dyn Trait: Trait` +} + +fn foo(x: T::A) -> B +where + T: Trait, +{ + x +} + +static X: u8 = 0; +fn main() { + let x = transmute::<&u8, &[u8; 1_000_000]>(&X); + println!("{:?}", x[100_000]); +} diff --git a/tests/ui/traits/new-solver/more-object-bound.stderr b/tests/ui/traits/new-solver/more-object-bound.stderr new file mode 100644 index 0000000000000..208fdecb08fc9 --- /dev/null +++ b/tests/ui/traits/new-solver/more-object-bound.stderr @@ -0,0 +1,19 @@ +error[E0283]: type annotations needed: cannot satisfy `dyn Trait: Trait` + --> $DIR/more-object-bound.rs:12:5 + | +LL | foo::>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: cannot satisfy `dyn Trait: Trait` +note: required by a bound in `foo` + --> $DIR/more-object-bound.rs:18:8 + | +LL | fn foo(x: T::A) -> B + | --- required by a bound in this function +LL | where +LL | T: Trait, + | ^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/new-solver/object-unsafety.rs b/tests/ui/traits/new-solver/object-unsafety.rs new file mode 100644 index 0000000000000..7bdd863a762c4 --- /dev/null +++ b/tests/ui/traits/new-solver/object-unsafety.rs @@ -0,0 +1,20 @@ +// compile-flags: -Ztrait-solver=next + +trait Setup { + type From: Copy; +} + +fn copy(from: &U::From) -> U::From { + *from +} + +pub fn copy_any(t: &T) -> T { + copy::>(t) + //~^ ERROR the trait bound `dyn Setup: Setup` is not satisfied +} + +fn main() { + let x = String::from("Hello, world"); + let y = copy_any(&x); + println!("{y}"); +} diff --git a/tests/ui/traits/new-solver/object-unsafety.stderr b/tests/ui/traits/new-solver/object-unsafety.stderr new file mode 100644 index 0000000000000..198ac623df8a6 --- /dev/null +++ b/tests/ui/traits/new-solver/object-unsafety.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `dyn Setup: Setup` is not satisfied + --> $DIR/object-unsafety.rs:12:12 + | +LL | copy::>(t) + | ^^^^^^^^^^^^^^^^^ the trait `Setup` is not implemented for `dyn Setup` + | +note: required by a bound in `copy` + --> $DIR/object-unsafety.rs:7:12 + | +LL | fn copy(from: &U::From) -> U::From { + | ^^^^^ required by this bound in `copy` +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | pub fn copy_any(t: &T) -> T where dyn Setup: Setup { + | ++++++++++++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`.