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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2384,7 +2384,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Some(ConstItemRhs::TypeConst(anon)) => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
None if attr::contains_name(attrs, sym::type_const) => {
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(
Expand Down
92 changes: 76 additions & 16 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))

let args = args::arg_expand_all(&default_early_dcx, at_args);

let Some(matches) = handle_options(&default_early_dcx, &args) else {
return;
let (matches, help_only) = match handle_options(&default_early_dcx, &args) {
HandledOptions::None => return,
HandledOptions::Normal(matches) => (matches, false),
HandledOptions::HelpOnly(matches) => (matches, true),
};

let sopts = config::build_session_options(&mut default_early_dcx, &matches);
Expand Down Expand Up @@ -291,6 +293,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
return early_exit();
}

// We have now handled all help options, exit
if help_only {
return early_exit();
}

if print_crate_info(codegen_backend, sess, has_input) == Compilation::Stop {
return early_exit();
}
Expand Down Expand Up @@ -1097,7 +1104,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
// Don't handle -W help here, because we might first load additional lints.
let debug_flags = matches.opt_strs("Z");
if debug_flags.iter().any(|x| *x == "help") {
describe_debug_flags();
describe_unstable_flags();
return true;
}

Expand Down Expand Up @@ -1137,8 +1144,8 @@ fn get_backend_from_raw_matches(
get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
}

fn describe_debug_flags() {
safe_println!("\nAvailable options:\n");
fn describe_unstable_flags() {
safe_println!("\nAvailable unstable options:\n");
print_flag_list("-Z", config::Z_OPTIONS);
}

Expand All @@ -1162,6 +1169,16 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
}
}

pub enum HandledOptions {
/// Parsing failed, or we parsed a flag causing an early exit
None,
/// Successful parsing
Normal(getopts::Matches),
/// Parsing succeeded, but we received one or more 'help' flags
/// The compiler should proceed only until a possible `-W help` flag has been processed
HelpOnly(getopts::Matches),
}

/// Process command line options. Emits messages as appropriate. If compilation
/// should continue, returns a getopts::Matches object parsed from args,
/// otherwise returns `None`.
Expand Down Expand Up @@ -1189,7 +1206,7 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
/// This does not need to be `pub` for rustc itself, but @chaosite needs it to
/// be public when using rustc as a library, see
/// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> HandledOptions {
// Parse with *all* options defined in the compiler, we don't worry about
// option stability here we just want to parse as much as possible.
let mut options = getopts::Options::new();
Expand Down Expand Up @@ -1235,26 +1252,69 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
// (unstable option being used on stable)
nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups());

if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
return None;
// Handle the special case of -Wall.
let wall = matches.opt_strs("W");
if wall.iter().any(|x| *x == "all") {
print_wall_help();
return HandledOptions::None;
}

if describe_flag_categories(early_dcx, &matches) {
return None;
if handle_help(&matches, args) {
return HandledOptions::HelpOnly(matches);
}

if matches.opt_strs("C").iter().any(|x| x == "passes=list") {
get_backend_from_raw_matches(early_dcx, &matches).print_passes();
return HandledOptions::None;
}

if matches.opt_present("version") {
version!(early_dcx, "rustc", &matches);
return None;
return HandledOptions::None;
}

warn_on_confusing_output_filename_flag(early_dcx, &matches, args);

Some(matches)
HandledOptions::Normal(matches)
}

/// Handle help options in the order they are provided, ignoring other flags. Returns if any options were handled
/// Handled options:
/// - `-h`/`--help`/empty arguments
/// - `-Z help`
/// - `-C help`
/// NOTE: `-W help` is NOT handled here, as additional lints may be loaded.
pub fn handle_help(matches: &getopts::Matches, args: &[String]) -> bool {
let opt_pos = |opt| matches.opt_positions(opt).first().copied();
let opt_help_pos = |opt| {
matches
.opt_strs_pos(opt)
.iter()
.filter_map(|(pos, oval)| if oval == "help" { Some(*pos) } else { None })
.next()
};
let help_pos = if args.is_empty() { Some(0) } else { opt_pos("h").or_else(|| opt_pos("help")) };
let zhelp_pos = opt_help_pos("Z");
let chelp_pos = opt_help_pos("C");
let print_help = || {
// Only show unstable options in --help if we accept unstable options.
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
};

let mut helps = [
(help_pos, &print_help as &dyn Fn()),
(zhelp_pos, &describe_unstable_flags),
(chelp_pos, &describe_codegen_flags),
];
helps.sort_by_key(|(pos, _)| pos.clone());
let mut printed_any = false;
for printer in helps.iter().filter_map(|(pos, func)| pos.is_some().then_some(func)) {
printer();
printed_any = true;
}
printed_any
}

/// Warn if `-o` is used without a space between the flag name and the value
Expand Down
18 changes: 15 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,13 +389,25 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| sym::rustc_partition_reused
| sym::rustc_partition_codegened
| sym::rustc_expected_cgu_reuse
| sym::rustc_nounwind,
| sym::rustc_nounwind
// crate-level attrs, are checked below
| sym::feature
| sym::register_tool
| sym::rustc_no_implicit_bounds
| sym::test_runner
| sym::reexport_test_harness_main
| sym::no_main
| sym::no_builtins
| sym::crate_type
| sym::compiler_builtins
| sym::profiler_runtime
| sym::needs_panic_runtime
| sym::panic_runtime
| sym::rustc_preserve_ub_checks,
..
] => {}
[name, rest@..] => {
match BUILTIN_ATTRIBUTE_MAP.get(name) {
// checked below
Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
Some(_) => {
if rest.len() > 0 && AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(name)) {
// Check if we tried to use a builtin attribute as an attribute namespace, like `#[must_use::skip]`.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
PathResult::Module(module) => {
// Consistency checks, analogous to `finalize_macro_resolutions`.
if let Some(initial_module) = import.imported_module.get() {
if module != initial_module && no_ambiguity {
if module != initial_module && no_ambiguity && !self.issue_145575_hack_applied {
span_bug!(import.span, "inconsistent resolution for an import");
}
} else if self.privacy_errors.is_empty() {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2126,6 +2126,7 @@ options! {
#[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")]
force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED],
"force use of unwind tables"),
help: bool = (false, parse_no_value, [UNTRACKED], "Print codegen options"),
incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
"enable incremental compilation"),
#[rustc_lint_opt_deny_field_access("documented to do nothing")]
Expand Down Expand Up @@ -2398,6 +2399,7 @@ options! {
environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
"explicitly enable the `cfg(target_thread_local)` directive"),
help: bool = (false, parse_no_value, [UNTRACKED], "Print unstable compiler options"),
higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED],
"allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"),
hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_trait_selection/src/traits/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,12 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
#[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx();
if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) {

if tcx.features().generic_const_exprs()
// Normalize type_const items even with feature `generic_const_exprs`.
&& !matches!(ct.kind(), ty::ConstKind::Unevaluated(uv) if tcx.is_type_const(uv.def))
|| !needs_normalization(self.selcx.infcx, &ct)
{
return ct;
}

Expand Down
2 changes: 2 additions & 0 deletions tests/crashes/138089.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//@ known-bug: #138089
//@ needs-rustc-debug-assertions

#![feature(generic_const_exprs)]
#![feature(min_generic_const_args)]
#![feature(inherent_associated_types)]
Expand Down
13 changes: 13 additions & 0 deletions tests/crashes/138226-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ known-bug: #138226
//@ needs-rustc-debug-assertions
#![feature(min_generic_const_args)]
#![feature(inherent_associated_types)]
struct Bar<const N: usize>;
impl<const N: usize> Bar<N> {
#[type_const]
const LEN: usize = 4;

fn bar() {
let _ = [0; Self::LEN];
}
}
13 changes: 13 additions & 0 deletions tests/crashes/138226.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ known-bug: #138226
//@ needs-rustc-debug-assertions
#![feature(min_generic_const_args)]
#![feature(inherent_associated_types)]
struct Foo<A, B>(A, B);
impl<A, B> Foo<A, B> {
#[type_const]
const LEN: usize = 4;

fn foo() {
let _ = [5; Self::LEN];
}
}
13 changes: 13 additions & 0 deletions tests/crashes/149809.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//@ known-bug: #149809
#![feature(min_generic_const_args)]
#![feature(inherent_associated_types)]
struct Qux<'a> {
x: &'a (),
}
impl<'a> Qux<'a> {
#[type_const]
const LEN: usize = 4;
fn foo(_: [u8; Qux::LEN]) {}
}

fn main() {}
11 changes: 11 additions & 0 deletions tests/crashes/150960.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ known-bug: #150960
#![feature(min_generic_const_args)]
struct Baz;
impl Baz {
#[type_const]
const LEN: usize = 4;

fn baz() {
let _ = [0; const { Self::LEN }];
}
}
30 changes: 30 additions & 0 deletions tests/run-make/rustc-help/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,34 @@ fn main() {
// Check the diff between `rustc --help` and `rustc --help -v`.
let help_v_diff = similar::TextDiff::from_lines(&help, &help_v).unified_diff().to_string();
diff().expected_file("help-v.diff").actual_text("actual", &help_v_diff).run();

// Check that all help options can be invoked at once
let codegen_help = bare_rustc().arg("-Chelp").run().stdout_utf8();
let unstable_help = bare_rustc().arg("-Zhelp").run().stdout_utf8();
let lints_help = bare_rustc().arg("-Whelp").run().stdout_utf8();
let expected_all = format!("{help}{codegen_help}{unstable_help}{lints_help}");
let all_help = bare_rustc().args(["--help", "-Chelp", "-Zhelp", "-Whelp"]).run().stdout_utf8();
diff()
.expected_text(
"(rustc --help && rustc -Chelp && rustc -Zhelp && rustc -Whelp)",
&expected_all,
)
.actual_text("(rustc --help -Chelp -Zhelp -Whelp)", &all_help)
.run();

// Check that the ordering of help options is respected
// Note that this is except for `-Whelp`, which always comes last
let expected_ordered_help = format!("{unstable_help}{codegen_help}{help}{lints_help}");
let ordered_help =
bare_rustc().args(["-Whelp", "-Zhelp", "-Chelp", "--help"]).run().stdout_utf8();
diff()
.expected_text(
"(rustc -Whelp && rustc -Zhelp && rustc -Chelp && rustc --help)",
&expected_ordered_help,
)
.actual_text("(rustc -Whelp -Zhelp -Chelp --help)", &ordered_help)
.run();

// Test that `rustc --help` does not suppress invalid flag errors
let help = bare_rustc().arg("--help --invalid-flag").run_fail().stdout_utf8();
}
27 changes: 27 additions & 0 deletions tests/ui/const-generics/mgca/assoc-const-projection-in-bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! regression test for <https://github.com/rust-lang/rust/issues/141014>
//@ run-pass
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]
#![allow(dead_code)]

trait Abc {}

trait A {
#[type_const]
const VALUE: usize;
}

impl<T: Abc> A for T {
#[type_const]
const VALUE: usize = 0;
}

trait S<const K: usize> {}

trait Handler<T: Abc>
where
(): S<{ <T as A>::VALUE }>,
{
}

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/const-generics/mgca/cyclic-type-const-151251.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ needs-rustc-debug-assertions

#![feature(min_generic_const_args)]
#![feature(generic_const_exprs)]
#![expect(incomplete_features)]

#[type_const]
const A: u8 = A;
//~^ ERROR overflow normalizing the unevaluated constant `A`

fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/const-generics/mgca/cyclic-type-const-151251.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0275]: overflow normalizing the unevaluated constant `A`
--> $DIR/cyclic-type-const-151251.rs:8:1
|
LL | const A: u8 = A;
| ^^^^^^^^^^^
|
= note: in case this is a recursive type alias, consider using a struct, enum, or union instead

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0275`.
12 changes: 12 additions & 0 deletions tests/ui/const-generics/mgca/size-of-generic-ptr-in-array-len.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! regression test for <https://github.com/rust-lang/rust/issues/147415>
#![expect(incomplete_features)]
#![feature(min_generic_const_args)]

fn foo<T>() {
[0; size_of::<*mut T>()];
//~^ ERROR: tuple constructor with invalid base path
[0; const { size_of::<*mut T>() }];
//~^ ERROR: generic parameters may not be used in const operations
}

fn main() {}
Loading
Loading