Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
9 changes: 9 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/crate_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
}

pub(crate) struct NoMainParser;

impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
const PATH: &[Symbol] = &[sym::no_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
}

pub(crate) struct RustcCoherenceIsCoreParser;

impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ use crate::attributes::codegen_attrs::{
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
WindowsSubsystemParser,
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser,
PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser,
TypeLengthLimitParser, WindowsSubsystemParser,
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
Expand Down Expand Up @@ -263,6 +263,7 @@ attribute_parsers!(
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoLinkParser>>,
Single<WithoutArgs<NoMainParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
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
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,9 @@ pub enum AttributeKind {
/// Represents `#[no_link]`
NoLink,

/// Represents `#[no_main]`
NoMain,

/// Represents `#[no_mangle]`
NoMangle(Span),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ impl AttributeKind {
NoCore(..) => No,
NoImplicitPrelude(..) => No,
NoLink => No,
NoMain => No,
NoMangle(..) => Yes, // Needed for rustdoc
NoStd(..) => No,
NonExhaustive(..) => Yes, // Needed for rustdoc
Expand Down
19 changes: 16 additions & 3 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::PatternComplexityLimit { .. }
| AttributeKind::NoCore { .. }
| AttributeKind::NoStd { .. }
| AttributeKind::NoMain
| AttributeKind::ObjcClass { .. }
| AttributeKind::ObjcSelector { .. }
| AttributeKind::RustcCoherenceIsCore(..)
Expand Down Expand Up @@ -389,13 +390,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
5 changes: 2 additions & 3 deletions compiler/rustc_passes/src/entry.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use rustc_ast::attr;
use rustc_ast::entry::EntryPointType;
use rustc_errors::codes::*;
use rustc_hir::attrs::AttributeKind;
Expand All @@ -7,7 +6,7 @@ use rustc_hir::{CRATE_HIR_ID, ItemId, Node, find_attr};
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, EntryFnType, sigpipe};
use rustc_span::{RemapPathScopeComponents, Span, sym};
use rustc_span::{RemapPathScopeComponents, Span};

use crate::errors::{ExternMain, MultipleRustcMain, NoMainErr};

Expand All @@ -30,7 +29,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
}

// If the user wants no main function at all, then stop here.
if attr::contains_name(tcx.hir_attrs(CRATE_HIR_ID), sym::no_main) {
if find_attr!(tcx.hir_attrs(CRATE_HIR_ID), AttributeKind::NoMain) {
return None;
}

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 }];
}
}
Loading
Loading