diff options
Diffstat (limited to 'compiler')
37 files changed, 516 insertions, 306 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 802a6fa3249..3e8fddd9954 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2284,6 +2284,54 @@ pub struct FnSig { pub span: Span, } +impl FnSig { + /// Return a span encompassing the header, or where to insert it if empty. + pub fn header_span(&self) -> Span { + match self.header.ext { + Extern::Implicit(span) | Extern::Explicit(_, span) => { + return self.span.with_hi(span.hi()); + } + Extern::None => {} + } + + match self.header.safety { + Safety::Unsafe(span) | Safety::Safe(span) => return self.span.with_hi(span.hi()), + Safety::Default => {} + }; + + if let Some(coroutine_kind) = self.header.coroutine_kind { + return self.span.with_hi(coroutine_kind.span().hi()); + } + + if let Const::Yes(span) = self.header.constness { + return self.span.with_hi(span.hi()); + } + + self.span.shrink_to_lo() + } + + /// The span of the header's safety, or where to insert it if empty. + pub fn safety_span(&self) -> Span { + match self.header.safety { + Safety::Unsafe(span) | Safety::Safe(span) => span, + Safety::Default => { + // Insert after the `coroutine_kind` if available. + if let Some(extern_span) = self.header.ext.span() { + return extern_span.shrink_to_lo(); + } + + // Insert right at the front of the signature. + self.header_span().shrink_to_hi() + } + } + } + + /// The span of the header's extern, or where to insert it if empty. + pub fn extern_span(&self) -> Span { + self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi()) + } +} + /// A constraint on an associated item. /// /// ### Examples @@ -3526,6 +3574,13 @@ impl Extern { None => Extern::Implicit(span), } } + + pub fn span(self) -> Option<Span> { + match self { + Extern::None => None, + Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), + } + } } /// A function header. @@ -3534,12 +3589,12 @@ impl Extern { /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). #[derive(Clone, Copy, Encodable, Decodable, Debug, Walkable)] pub struct FnHeader { - /// Whether this is `unsafe`, or has a default safety. - pub safety: Safety, - /// Whether this is `async`, `gen`, or nothing. - pub coroutine_kind: Option<CoroutineKind>, /// The `const` keyword, if any pub constness: Const, + /// Whether this is `async`, `gen`, or nothing. + pub coroutine_kind: Option<CoroutineKind>, + /// Whether this is `unsafe`, or has a default safety. + pub safety: Safety, /// The `extern` keyword and corresponding ABI string, if any. pub ext: Extern, } @@ -3553,38 +3608,6 @@ impl FnHeader { || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } - - /// Return a span encompassing the header, or none if all options are default. - pub fn span(&self) -> Option<Span> { - fn append(a: &mut Option<Span>, b: Span) { - *a = match a { - None => Some(b), - Some(x) => Some(x.to(b)), - } - } - - let mut full_span = None; - - match self.safety { - Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span), - Safety::Default => {} - }; - - if let Some(coroutine_kind) = self.coroutine_kind { - append(&mut full_span, coroutine_kind.span()); - } - - if let Const::Yes(span) = self.constness { - append(&mut full_span, span); - } - - match self.ext { - Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span), - Extern::None => {} - } - - full_span - } } impl Default for FnHeader { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3674814b796..bb6b25baf01 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1536,7 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::LangItem::Range } } - (None, Some(..), Closed) => hir::LangItem::RangeToInclusive, + (None, Some(..), Closed) => { + if self.tcx.features().new_range() { + hir::LangItem::RangeToInclusiveCopy + } else { + hir::LangItem::RangeToInclusive + } + } (Some(e1), Some(e2), Closed) => { if self.tcx.features().new_range() { hir::LangItem::RangeInclusiveCopy @@ -1560,13 +1566,26 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let fields = self.arena.alloc_from_iter( - e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map( - |(s, e)| { + e1.iter() + .map(|e| (sym::start, e)) + .chain(e2.iter().map(|e| { + ( + if matches!( + lang_item, + hir::LangItem::RangeInclusiveCopy | hir::LangItem::RangeToInclusiveCopy + ) { + sym::last + } else { + sym::end + }, + e, + ) + })) + .map(|(s, e)| { let expr = self.lower_expr(e); let ident = Ident::new(s, self.lower_span(e.span)); self.expr_field(ident, expr, e.span) - }, - ), + }), ); hir::ExprKind::Struct( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 72f20a95ff0..4e2243e8787 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2101,17 +2101,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { return; } - if self.tcx.features().more_maybe_bounds() { - return; - } } RelaxedBoundPolicy::Forbidden(reason) => { - if self.tcx.features().more_maybe_bounds() { - return; - } - match reason { RelaxedBoundForbiddenReason::TraitObjectTy => { + if self.tcx.features().more_maybe_bounds() { + return; + } + self.dcx().span_err( span, "relaxed bounds are not permitted in trait object types", @@ -2119,6 +2116,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return; } RelaxedBoundForbiddenReason::SuperTrait => { + if self.tcx.features().more_maybe_bounds() { + return; + } + let mut diag = self.dcx().struct_span_err( span, "relaxed bounds are not permitted in supertrait bounds", diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index e5f1fcdc4b4..8dcf3e3aa38 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention - ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body .invalid = the invalid body @@ -66,6 +64,19 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect +ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list + +ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions + .label = `extern "{$abi}"` because of this + .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + +ast_passes_c_variadic_must_be_unsafe = + functions with a C variable argument list must be unsafe + .suggestion = add the `unsafe` keyword to this definition + +ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions + .help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic .const = `const` because of this .variadic = C-variadic because of this @@ -84,6 +95,10 @@ ast_passes_const_without_body = ast_passes_constraint_on_negative_bound = associated type constraints not allowed on negative bounds +ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic + .const = `{$coroutine_kind}` because of this + .variadic = C-variadic because of this + ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses .label = not supported .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 538918a890d..a6ef89b553d 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -492,7 +492,7 @@ impl<'a> AstValidator<'a> { } if !spans.is_empty() { - let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo()); + let header_span = sig.header_span(); let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); let padding = if header_span.is_empty() { "" } else { " " }; @@ -685,22 +685,53 @@ impl<'a> AstValidator<'a> { }); } + if let Some(coroutine_kind) = sig.header.coroutine_kind { + self.dcx().emit_err(errors::CoroutineAndCVariadic { + spans: vec![coroutine_kind.span(), variadic_param.span], + coroutine_kind: coroutine_kind.as_str(), + coroutine_span: coroutine_kind.span(), + variadic_span: variadic_param.span, + }); + } + match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free => match sig.header.ext { - Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _) - | Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _) - | Extern::Implicit(_) - if matches!(sig.header.safety, Safety::Unsafe(_)) => - { - return; + Extern::Implicit(_) => { + if !matches!(sig.header.safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + span: variadic_param.span, + unsafe_span: sig.safety_span(), + }); + } } - _ => {} - }, - FnCtxt::Assoc(_) => {} - }; + Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => { + if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) { + self.dcx().emit_err(errors::CVariadicBadExtern { + span: variadic_param.span, + abi: symbol_unescaped, + extern_span: sig.extern_span(), + }); + } - self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span }); + if !matches!(sig.header.safety, Safety::Unsafe(_)) { + self.dcx().emit_err(errors::CVariadicMustBeUnsafe { + span: variadic_param.span, + unsafe_span: sig.safety_span(), + }); + } + } + Extern::None => { + let err = errors::CVariadicNoExtern { span: variadic_param.span }; + self.dcx().emit_err(err); + } + }, + FnCtxt::Assoc(_) => { + // For now, C variable argument lists are unsupported in associated functions. + let err = errors::CVariadicAssociatedFunction { span: variadic_param.span }; + self.dcx().emit_err(err); + } + } } fn check_item_named(&self, ident: Ident, kind: &str) { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 476ed27a10e..ae805042c54 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -319,13 +319,47 @@ pub(crate) struct ExternItemAscii { } #[derive(Diagnostic)] -#[diag(ast_passes_bad_c_variadic)] -pub(crate) struct BadCVariadic { +#[diag(ast_passes_c_variadic_associated_function)] +pub(crate) struct CVariadicAssociatedFunction { #[primary_span] pub span: Span, } #[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_no_extern)] +#[help] +pub(crate) struct CVariadicNoExtern { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_must_be_unsafe)] +pub(crate) struct CVariadicMustBeUnsafe { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_c_variadic_bad_extern)] +#[help] +pub(crate) struct CVariadicBadExtern { + #[primary_span] + pub span: Span, + pub abi: Symbol, + #[label] + pub extern_span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_item_underscore)] pub(crate) struct ItemUnderscore<'a> { #[primary_span] @@ -660,6 +694,18 @@ pub(crate) struct ConstAndCVariadic { } #[derive(Diagnostic)] +#[diag(ast_passes_coroutine_and_c_variadic)] +pub(crate) struct CoroutineAndCVariadic { + #[primary_span] + pub spans: Vec<Span>, + pub coroutine_kind: &'static str, + #[label(ast_passes_const)] + pub coroutine_span: Span, + #[label(ast_passes_variadic)] + pub variadic_span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_pattern_in_foreign, code = E0130)] // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`) pub(crate) struct PatternInForeign { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index ffdacff7152..d5d51f2e79a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -218,6 +218,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser { sym::rustc_std_internal_symbol, // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity sym::rustc_align, + sym::rustc_align_static, // obviously compatible with self sym::naked, // documentation diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 23aabd15597..0330e2515c7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -331,3 +331,30 @@ impl<S: Stage> AttributeParser<S> for AlignParser { Some(AttributeKind::Align { align, span }) } } + +#[derive(Default)] +pub(crate) struct AlignStaticParser(AlignParser); + +impl AlignStaticParser { + const PATH: &'static [Symbol] = &[sym::rustc_align_static]; + const TEMPLATE: AttributeTemplate = AlignParser::TEMPLATE; + + fn parse<'c, S: Stage>( + &mut self, + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) { + self.0.parse(cx, args) + } +} + +impl<S: Stage> AttributeParser<S> for AlignStaticParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(Self::PATH, Self::TEMPLATE, Self::parse)]; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]); + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + let (align, span) = self.0.0?; + Some(AttributeKind::Align { align, span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 98e86838a3a..d2b35090135 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -50,7 +50,7 @@ use crate::attributes::proc_macro_attrs::{ ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser, }; use crate::attributes::prototype::CustomMirParser; -use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser}; use crate::attributes::rustc_internal::{ RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart, RustcObjectLifetimeDefaultParser, @@ -152,6 +152,7 @@ attribute_parsers!( pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start AlignParser, + AlignStaticParser, BodyStabilityParser, ConfusablesParser, ConstStabilityParser, diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 6415e55e0b0..a6c8e7d29cc 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -565,6 +565,7 @@ fn make_format_args( &used, &args, &pieces, + &invalid_refs, detect_foreign_fmt, str_style, fmt_str, @@ -645,6 +646,7 @@ fn report_missing_placeholders( used: &[bool], args: &FormatArguments, pieces: &[parse::Piece<'_>], + invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)], detect_foreign_fmt: bool, str_style: Option<usize>, fmt_str: &str, @@ -762,6 +764,31 @@ fn report_missing_placeholders( diag.span_label(fmt_span, "formatting specifier missing"); } + if !found_foreign && invalid_refs.is_empty() { + // Show example if user didn't use any format specifiers + let show_example = used.iter().all(|used| !used); + + if !show_example { + if unused.len() > 1 { + diag.note(format!("consider adding {} format specifiers", unused.len())); + } + } else { + let original_fmt_str = + if fmt_str.len() >= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" }; + + let msg = if unused.len() == 1 { + "a format specifier".to_string() + } else { + format!("{} format specifiers", unused.len()) + }; + + let sugg = format!("\"{}{}\"", original_fmt_str, "{}".repeat(unused.len())); + let msg = format!("format specifiers use curly braces, consider adding {msg}"); + + diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect); + } + } + diag.emit(); } diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 37bab5be542..11b868f81a9 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,3 +1,5 @@ +//! The implementation of built-in macros which relate to the file system. + use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; @@ -11,9 +13,11 @@ use rustc_expand::base::{ }; use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::lexer::StripTokens; +use rustc_parse::parser::ForceCollect; use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; +use rustc_session::parse::ParseSess; use rustc_span::source_map::SourceMap; use rustc_span::{ByteSymbol, Pos, Span, Symbol}; use smallvec::SmallVec; @@ -23,11 +27,7 @@ use crate::util::{ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, }; -// These macros all relate to the file system; they either return -// the column/row/filename of the expression, or they include -// a given file into the current one. - -/// line!(): expands to the current line number +/// Expand `line!()` to the current line number. pub(crate) fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, @@ -42,7 +42,7 @@ pub(crate) fn expand_line( ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32))) } -/* column!(): expands to the current column number */ +/// Expand `column!()` to the current column number. pub(crate) fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, @@ -57,9 +57,7 @@ pub(crate) fn expand_column( ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))) } -/// file!(): expands to the current filename */ -/// The source_file (`loc.file`) contains a bunch more information we could spit -/// out if we wanted. +/// Expand `file!()` to the current filename. pub(crate) fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, @@ -81,6 +79,7 @@ pub(crate) fn expand_file( ))) } +/// Expand `stringify!($input)`. pub(crate) fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, @@ -91,6 +90,7 @@ pub(crate) fn expand_stringify( ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))) } +/// Expand `module_path!()` to (a textual representation of) the current module path. pub(crate) fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, @@ -104,9 +104,9 @@ pub(crate) fn expand_mod( ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))) } -/// include! : parse the given file as an expr -/// This is generally a bad idea because it's going to behave -/// unhygienically. +/// Expand `include!($input)`. +/// +/// This works in item and expression position. Notably, it doesn't work in pattern position. pub(crate) fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -116,39 +116,48 @@ pub(crate) fn expand_include<'cx>( let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else { return ExpandResult::Retry(()); }; - let file = match mac { - Ok(file) => file, + let path = match mac { + Ok(path) => path, Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)), }; // The file will be added to the code map by the parser - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, + let path = match resolve_path(&cx.sess, path.as_str(), sp) { + Ok(path) => path, Err(err) => { let guar = err.emit(); return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, - // then the path of `bar.rs` should be relative to the directory of `file`. + // then the path of `bar.rs` should be relative to the directory of `path`. // See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion. // `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained. - let dir_path = file.parent().unwrap_or(&file).to_owned(); + let dir_path = path.parent().unwrap_or(&path).to_owned(); cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path)); cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None }; struct ExpandInclude<'a> { - p: Parser<'a>, + psess: &'a ParseSess, + path: PathBuf, node_id: ast::NodeId, + span: Span, } impl<'a> MacResult for ExpandInclude<'a> { - fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> { - let expr = parse_expr(&mut self.p).ok()?; - if self.p.token != token::Eof { - self.p.psess.buffer_lint( + fn make_expr(self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> { + let mut p = unwrap_or_emit_fatal(new_parser_from_file( + self.psess, + &self.path, + // Don't strip frontmatter for backward compatibility, `---` may be the start of a + // manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either. + StripTokens::Shebang, + Some(self.span), + )); + let expr = parse_expr(&mut p).ok()?; + if p.token != token::Eof { + p.psess.buffer_lint( INCOMPLETE_INCLUDE, - self.p.token.span, + p.token.span, self.node_id, BuiltinLintDiag::IncompleteInclude, ); @@ -156,24 +165,27 @@ pub(crate) fn expand_include<'cx>( Some(expr) } - fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { + fn make_items(self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> { + let mut p = unwrap_or_emit_fatal(new_parser_from_file( + self.psess, + &self.path, + StripTokens::ShebangAndFrontmatter, + Some(self.span), + )); let mut ret = SmallVec::new(); loop { - match self.p.parse_item(ForceCollect::No) { + match p.parse_item(ForceCollect::No) { Err(err) => { err.emit(); break; } Ok(Some(item)) => ret.push(item), Ok(None) => { - if self.p.token != token::Eof { - self.p - .dcx() - .create_err(errors::ExpectedItem { - span: self.p.token.span, - token: &pprust::token_to_string(&self.p.token), - }) - .emit(); + if p.token != token::Eof { + p.dcx().emit_err(errors::ExpectedItem { + span: p.token.span, + token: &pprust::token_to_string(&p.token), + }); } break; @@ -184,10 +196,17 @@ pub(crate) fn expand_include<'cx>( } } - ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id })) + ExpandResult::Ready(Box::new(ExpandInclude { + psess: cx.psess(), + path, + node_id: cx.current_expansion.lint_node_id, + span: sp, + })) } -/// `include_str!`: read the given file, insert it as a literal string expr +/// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal. +/// +/// This works in expression, pattern and statement position. pub(crate) fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, @@ -206,6 +225,7 @@ pub(crate) fn expand_include_str( Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); + // MacEager converts the expr into a pat if need be. MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } Err(utf8err) => { @@ -218,6 +238,9 @@ pub(crate) fn expand_include_str( }) } +/// Expand `include_bytes!($input)` to the content of the file given by path `$input`. +/// +/// This works in expression, pattern and statement position. pub(crate) fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, @@ -237,6 +260,7 @@ pub(crate) fn expand_include_bytes( // Don't care about getting the span for the raw bytes, // because the console can't really show them anyway. let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes))); + // MacEager converts the expr into a pat if need be. MacEager::expr(expr) } Err(dummy) => dummy, diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 619277eba8b..7fe8fc122b3 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -81,6 +81,8 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { if global.to_rvalue().get_type() != val_llty { global.to_rvalue().set_type(val_llty); } + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, global, alloc.align); global.global_set_initializer_rvalue(value); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 9ec7b0f80ae..dc9bb743560 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -452,6 +452,8 @@ impl<'ll> CodegenCx<'ll, '_> { self.statics_to_rauw.borrow_mut().push((g, new_g)); new_g }; + + // NOTE: Alignment from attributes has already been applied to the allocation. set_global_alignment(self, g, alloc.align); llvm::set_initializer(g, v); diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6ec85648d6d..ebcdb9461d0 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -953,6 +953,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // # Global allocations if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { + // NOTE: `static` alignment from attributes has already been applied to the allocation. let (size, align) = global_alloc.size_and_align(*self.tcx, self.typing_env); let mutbl = global_alloc.mutability(*self.tcx, self.typing_env); let kind = match global_alloc { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 72bee345406..f667823723c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer}; +use rustc_middle::mir::interpret::{AllocInit, Allocation, GlobalAlloc, InterpResult, Pointer}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{TyCtxt, TypeVisitable, TypeVisitableExt}; use tracing::debug; @@ -38,7 +38,14 @@ pub(crate) fn create_static_alloc<'tcx>( static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { - let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit, ())?; + // Inherit size and align from the `GlobalAlloc::Static` so we can avoid duplicating + // the alignment attribute logic. + let (size, align) = + GlobalAlloc::Static(static_def_id.into()).size_and_align(*ecx.tcx, ecx.typing_env); + assert_eq!(size, layout.size); + assert!(align >= layout.align.abi); + + let alloc = Allocation::try_new(size, align, AllocInit::Uninit, ())?; let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into()); assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index f3ed6042105..d00a4c35834 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -51,6 +51,7 @@ use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; use rustc_middle::ty::TyCtxt; +use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot, @@ -1288,10 +1289,15 @@ fn warn_on_confusing_output_filename_flag( fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { - Input::File(file) => new_parser_from_file(&sess.psess, file, None), - Input::Str { name, input } => { - new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) + Input::File(file) => { + new_parser_from_file(&sess.psess, file, StripTokens::ShebangAndFrontmatter, None) } + Input::Str { name, input } => new_parser_from_source_str( + &sess.psess, + name.clone(), + input.clone(), + StripTokens::ShebangAndFrontmatter, + ), }); parser.parse_inner_attributes() } diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 19f3cdbc549..79ab3cab22c 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -4,6 +4,7 @@ use std::path::{self, Path, PathBuf}; use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_attr_parsing::validate_attr; use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_parse::lexer::StripTokens; use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::Session; use rustc_session::parse::ParseSess; @@ -67,8 +68,12 @@ pub(crate) fn parse_external_mod( } // Actually parse the external file as a module. - let mut parser = - unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span))); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file( + &sess.psess, + &mp.file_path, + StripTokens::ShebangAndFrontmatter, + Some(span), + )); let (inner_attrs, items, inner_span) = parser.parse_mod(exp!(Eof)).map_err(|err| ModError::ParserError(err))?; attrs.extend(inner_attrs); diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5b1d3d6d35b..295573f4492 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; -use rustc_parse::lexer::nfc_normalize; +use rustc_parse::lexer::{StripTokens, nfc_normalize}; use rustc_parse::parser::Parser; use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_proc_macro::bridge::{ @@ -485,8 +485,13 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = - unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned())); + + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( + self.psess(), + name, + s.to_owned(), + StripTokens::Nothing, + )); let first_span = parser.token.span.data(); let minus_present = parser.eat(exp!(Minus)); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e81003b1897..129ab7eccb5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -621,6 +621,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)), + gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)), ungated!( unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 4f35bf63a1a..93e5588146e 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -632,6 +632,8 @@ declare_features! ( (unstable, simd_ffi, "1.0.0", Some(27731)), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844)), + /// Allows using `#[rustc_align_static(...)]` on static items. + (unstable, static_align, "CURRENT_RUSTC_VERSION", Some(146177)), /// Allows attributes on expressions and non-item statements. (unstable, stmt_expr_attributes, "1.6.0", Some(15701)), /// Allows lints part of the strict provenance effort. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ae03121e5f7..75551fe4c19 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2616,6 +2616,18 @@ impl Expr<'_> { ) | ( ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusiveCopy, _), + [val2], + StructTailExpr::None, + ), + ) + | ( + ExprKind::Struct( QPath::LangItem(LangItem::RangeFrom, _), [val1], StructTailExpr::None, @@ -2705,7 +2717,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { | LangItem::RangeToInclusive | LangItem::RangeCopy | LangItem::RangeFromCopy - | LangItem::RangeInclusiveCopy, + | LangItem::RangeInclusiveCopy + | LangItem::RangeToInclusiveCopy, .. ) ), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 0464665b41f..67d2f15d414 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -422,6 +422,7 @@ language_item_table! { RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None; RangeCopy, sym::RangeCopy, range_copy_struct, Target::Struct, GenericRequirement::None; RangeInclusiveCopy, sym::RangeInclusiveCopy, range_inclusive_copy_struct, Target::Struct, GenericRequirement::None; + RangeToInclusiveCopy, sym::RangeToInclusiveCopy, range_to_inclusive_copy_struct, Target::Struct, GenericRequirement::None; String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index b59dc4bd132..126ffabd448 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -174,12 +174,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } }; - if let Node::TraitItem(item) = node { - let mut bounds = Vec::new(); - icx.lowerer().add_default_trait_item_bounds(item, &mut bounds); - predicates.extend(bounds); - } - let generics = tcx.generics_of(def_id); // Below we'll consider the bounds on the type parameters (including `Self`) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index d14aef8ace4..99dc8e6e522 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,12 +1,13 @@ +use std::assert_matches::assert_matches; use std::ops::ControlFlow; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; +use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_hir::{AmbigArg, PolyTraitRef}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -230,122 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds - /// or associated items. - /// - /// To keep backward compatibility with existing code, `experimental_default_bounds` bounds - /// should be added everywhere, including super bounds. However this causes a huge performance - /// costs. For optimization purposes instead of adding default supertraits, bounds - /// are added to the associated items: - /// - /// ```ignore(illustrative) - /// // Default bounds are generated in the following way: - /// trait Trait { - /// fn foo(&self) where Self: Leak {} - /// } - /// - /// // instead of this: - /// trait Trait: Leak { - /// fn foo(&self) {} - /// } - /// ``` - /// It is not always possible to do this because of backward compatibility: - /// - /// ```ignore(illustrative) - /// pub trait Trait<Rhs = Self> {} - /// pub trait Trait1 : Trait {} - /// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait` - /// ``` - /// - /// or: - /// - /// ```ignore(illustrative) - /// trait Trait { - /// type Type where Self: Sized; - /// } - /// trait Trait2<T> : Trait<Type = T> {} - /// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type` - /// ``` - /// - /// Therefore, `experimental_default_bounds` are still being added to supertraits if - /// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header. - fn requires_default_supertraits( - &self, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], - hir_generics: &'tcx hir::Generics<'tcx>, - ) -> bool { - struct TraitInfoCollector; - - impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector { - type Result = ControlFlow<()>; - - fn visit_assoc_item_constraint( - &mut self, - _constraint: &'tcx hir::AssocItemConstraint<'tcx>, - ) -> Self::Result { - ControlFlow::Break(()) - } - - fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result { - if matches!( - &t.kind, - hir::TyKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. }, - )) - ) { - return ControlFlow::Break(()); - } - hir::intravisit::walk_ty(self, t) - } - } - - let mut found = false; - for bound in hir_bounds { - found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break(); - } - found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break(); - found - } - - /// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if - /// they are not added as super trait bounds to the trait itself. See - /// `requires_default_supertraits` for more information. - pub(crate) fn add_default_trait_item_bounds( - &self, - trait_item: &hir::TraitItem<'tcx>, - bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - ) { - let tcx = self.tcx(); - if !tcx.sess.opts.unstable_opts.experimental_default_bounds { - return; - } - - let parent = tcx.local_parent(trait_item.hir_id().owner.def_id); - let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else { - unreachable!(); - }; - - let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), - hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), - _ => unreachable!(), - }; - - if !self.requires_default_supertraits(trait_bounds, trait_generics) { - let self_ty_where_predicates = (parent, trait_item.generics.predicates); - self.add_default_traits( - bounds, - tcx.types.self_param, - &[], - Some(self_ty_where_predicates), - trait_item.span, - ); - } - } - - /// Lazily sets `experimental_default_bounds` to true on trait super bounds. - /// See `requires_default_supertraits` for more information. + /// Adds `experimental_default_bounds` bounds to the supertrait bounds. pub(crate) fn add_default_super_traits( &self, trait_def_id: LocalDefId, @@ -354,21 +240,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_generics: &'tcx hir::Generics<'tcx>, span: Span, ) { - if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds { + assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias); + + // Supertraits for auto trait are unsound according to the unstable book: + // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits + if self.tcx().trait_is_auto(trait_def_id.to_def_id()) { return; } - assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias)); - if self.requires_default_supertraits(hir_bounds, hir_generics) { - let self_ty_where_predicates = (trait_def_id, hir_generics.predicates); - self.add_default_traits( - bounds, - self.tcx().types.self_param, - hir_bounds, - Some(self_ty_where_predicates), - span, - ); - } + self.add_default_traits( + bounds, + self.tcx().types.self_param, + hir_bounds, + Some((trait_def_id, hir_generics.predicates)), + span, + ); } pub(crate) fn add_default_traits( diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index 33f406e2113..9cd7134659c 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -130,7 +130,22 @@ impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> { impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> { type Output = core::range::RangeInclusive<usize>; #[inline] + #[cfg(bootstrap)] fn into_slice_idx(self) -> Self::Output { core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } } + #[inline] + #[cfg(not(bootstrap))] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeInclusive { start: self.start.index(), last: self.last.index() } + } +} + +#[cfg(all(feature = "nightly", not(bootstrap)))] +impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeToInclusive<I> { + type Output = core::range::RangeToInclusive<usize>; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeToInclusive { last: self.last.index() } + } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 4c820b8877b..b52c5b4cd66 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -13,7 +13,8 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::new_parser_from_simple_source_str; +use rustc_parse::lexer::StripTokens; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; @@ -68,7 +69,8 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg { }; } - match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { + match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing) + { Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,13 +168,15 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) { - Ok(parser) => parser, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - expected_error(); - } - }; + let mut parser = + match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing) + { + Ok(parser) => parser, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + expected_error(); + } + }; let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => meta_item, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 6d9751d7d4d..d39219bfd66 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -28,6 +28,7 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepsType; use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; +use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; @@ -52,10 +53,18 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate { let mut krate = sess .time("parse_crate", || { let mut parser = unwrap_or_emit_fatal(match &sess.io.input { - Input::File(file) => new_parser_from_file(&sess.psess, file, None), - Input::Str { input, name } => { - new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) - } + Input::File(file) => new_parser_from_file( + &sess.psess, + file, + StripTokens::ShebangAndFrontmatter, + None, + ), + Input::Str { input, name } => new_parser_from_source_str( + &sess.psess, + name.clone(), + input.clone(), + StripTokens::ShebangAndFrontmatter, + ), }); parser.parse_crate_mod() }) diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 5513c703f1d..93f067d0983 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { .explicit_super_predicates_of(def_id) .iter_identity_copied() .filter_map(|(pred, _)| pred.as_trait_clause()) - .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized)); + .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized)) + .filter(|pred| !cx.tcx.is_default_trait(pred.def_id())); if direct_super_traits_iter.count() > 1 { cx.emit_span_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bed99a4ff2a..9762e0f21da 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -386,7 +386,16 @@ impl<'tcx> GlobalAlloc<'tcx> { .expect("statics should not have generic parameters"); let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); assert!(layout.is_sized()); - (layout.size, layout.align.abi) + + // Take over-alignment from attributes into account. + let align = match tcx.codegen_fn_attrs(def_id).alignment { + Some(align_from_attribute) => { + Ord::max(align_from_attribute, layout.align.abi) + } + None => layout.align.abi, + }; + + (layout.size, align) } } GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a7d99f513a1..f9d0a5f0a3b 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -78,8 +78,9 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option<Self> { let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir { // see notes on #41697 below - let node_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + let node_path = ty::print::with_no_trimmed_paths!( + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())) + ); filters.split('|').any(|or_filter| { or_filter.split('&').all(|and_filter| { let and_filter_trimmed = and_filter.trim(); @@ -173,9 +174,10 @@ impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { // trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`. pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { // see notes on #41697 above - let def_path = ty::print::with_forced_impl_filename_line!( - self.tcx().def_path_str(body.source.def_id()) - ); + let def_path = + ty::print::with_no_trimmed_paths!(ty::print::with_forced_impl_filename_line!( + self.tcx().def_path_str(body.source.def_id()) + )); // ignore-tidy-odd-backticks the literal below is fine write!(w, "// MIR for `{def_path}")?; match body.source.promoted { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f5f081efc49..51019db7c00 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -45,7 +45,7 @@ pub(crate) struct UnmatchedDelim { } /// Which tokens should be stripped before lexing the tokens. -pub(crate) enum StripTokens { +pub enum StripTokens { /// Strip both shebang and frontmatter. ShebangAndFrontmatter, /// Strip the shebang but not frontmatter. diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index d8792d7af4c..88b67d792de 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -54,29 +54,18 @@ pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T { } } -/// Creates a new parser from a source string. On failure, the errors must be consumed via -/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are -/// dropped. -pub fn new_parser_from_source_str( - psess: &ParseSess, - name: FileName, - source: String, -) -> Result<Parser<'_>, Vec<Diag<'_>>> { - let source_file = psess.source_map().new_source_file(name, source); - new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter) -} - -/// Creates a new parser from a simple (no shebang, no frontmatter) source string. +/// Creates a new parser from a source string. /// /// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`, /// etc., otherwise a panic will occur when they are dropped. -pub fn new_parser_from_simple_source_str( +pub fn new_parser_from_source_str( psess: &ParseSess, name: FileName, source: String, + strip_tokens: StripTokens, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let source_file = psess.source_map().new_source_file(name, source); - new_parser_from_source_file(psess, source_file, StripTokens::Nothing) + new_parser_from_source_file(psess, source_file, strip_tokens) } /// Creates a new parser from a filename. On failure, the errors must be consumed via @@ -87,6 +76,7 @@ pub fn new_parser_from_simple_source_str( pub fn new_parser_from_file<'a>( psess: &'a ParseSess, path: &Path, + strip_tokens: StripTokens, sp: Option<Span>, ) -> Result<Parser<'a>, Vec<Diag<'a>>> { let sm = psess.source_map(); @@ -110,7 +100,7 @@ pub fn new_parser_from_file<'a>( } err.emit(); }); - new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter) + new_parser_from_source_file(psess, source_file, strip_tokens) } pub fn utf8_error<E: EmissionGuarantee>( @@ -172,6 +162,9 @@ fn new_parser_from_source_file( Ok(parser) } +/// Given a source string, produces a sequence of token trees. +/// +/// NOTE: This only strips shebangs, not frontmatter! pub fn source_str_to_stream( psess: &ParseSess, name: FileName, @@ -179,13 +172,16 @@ pub fn source_str_to_stream( override_span: Option<Span>, ) -> Result<TokenStream, Vec<Diag<'_>>> { let source_file = psess.source_map().new_source_file(name, source); - // used mainly for `proc_macro` and the likes, not for our parsing purposes, so don't parse - // frontmatters as frontmatters, but for compatibility reason still strip the shebang + // FIXME(frontmatter): Consider stripping frontmatter in a future edition. We can't strip them + // in the current edition since that would be breaking. + // See also <https://github.com/rust-lang/rust/issues/145520>. + // Alternatively, stop stripping shebangs here, too, if T-lang and crater approve. source_file_to_stream(psess, source_file, override_span, StripTokens::Shebang) } -/// Given a source file, produces a sequence of token trees. Returns any buffered errors from -/// parsing the token stream. +/// Given a source file, produces a sequence of token trees. +/// +/// Returns any buffered errors from parsing the token stream. fn source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Arc<SourceFile>, diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a6e7266e71b..e645fb47b9e 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -22,6 +22,7 @@ use rustc_span::{ }; use termcolor::WriteColor; +use crate::lexer::StripTokens; use crate::parser::{ForceCollect, Parser}; use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; @@ -35,6 +36,7 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { psess, PathBuf::from("bogofile").into(), source_str, + StripTokens::Nothing, )) } @@ -2240,7 +2242,7 @@ fn parse_item_from_source_str( source: String, psess: &ParseSess, ) -> PResult<'_, Option<Box<ast::Item>>> { - unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing)) .parse_item(ForceCollect::No) } @@ -2520,7 +2522,8 @@ fn ttdelim_span() { source: String, psess: &ParseSess, ) -> PResult<'_, Box<ast::Expr>> { - unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing)) + .parse_expr() } create_default_session_globals_then(|| { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index afd08319738..ab7885905a6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -501,6 +501,10 @@ passes_repr_align_should_be_align = `#[repr(align(...))]` is not supported on {$item} .help = use `#[rustc_align(...)]` instead +passes_repr_align_should_be_align_static = + `#[repr(align(...))]` is not supported on {$item} + .help = use `#[rustc_align_static(...)]` instead + passes_repr_conflicting = conflicting representation hints diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 487bdd2a888..38a6b4b16c9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1606,12 +1606,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ReprAttr::ReprAlign(align) => { match target { Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) => { + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { self.dcx().emit_err(errors::ReprAlignShouldBeAlign { span: *repr_span, item: target.plural_name(), }); } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { hint_span: *repr_span, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 23dcabef1a1..2da4b6f52cf 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1610,6 +1610,15 @@ pub(crate) struct ReprAlignShouldBeAlign { } #[derive(Diagnostic)] +#[diag(passes_repr_align_should_be_align_static)] +pub(crate) struct ReprAlignShouldBeAlignStatic { + #[primary_span] + #[help] + pub span: Span, + pub item: &'static str, +} + +#[derive(Diagnostic)] #[diag(passes_custom_mir_phase_requires_dialect)] pub(crate) struct CustomMirPhaseRequiresDialect { #[primary_span] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e5108d8b7e9..cdb0b5b58da 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -7,7 +7,7 @@ use std::ops::Deref; use std::{fmt, str}; use rustc_arena::DroplessArena; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; @@ -21,18 +21,17 @@ mod tests; // The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`. symbols! { - // This list includes things that are definitely keywords (e.g. `if`), - // a few things that are definitely not keywords (e.g. the empty symbol, - // `{{root}}`) and things where there is disagreement between people and/or - // documents (such as the Rust Reference) about whether it is a keyword - // (e.g. `_`). + // This list includes things that are definitely keywords (e.g. `if`), a + // few things that are definitely not keywords (e.g. `{{root}}`) and things + // where there is disagreement between people and/or documents (such as the + // Rust Reference) about whether it is a keyword (e.g. `_`). // // If you modify this list, adjust any relevant `Symbol::{is,can_be}_*` // predicates and `used_keywords`. Also consider adding new keywords to the // `ui/parser/raw/raw-idents.rs` test. Keywords { - // Special reserved identifiers used internally for elided lifetimes, - // unnamed method parameters, crate root module, error recovery etc. + // Special reserved identifiers used internally for unnamed method + // parameters, crate root module, etc. // Matching predicates: `is_special`/`is_reserved` // // tidy-alphabetical-start @@ -326,6 +325,7 @@ symbols! { RangeSub, RangeTo, RangeToInclusive, + RangeToInclusiveCopy, Rc, RcWeak, Ready, @@ -1280,6 +1280,7 @@ symbols! { lang, lang_items, large_assignments, + last, lateout, lazy_normalization_consts, lazy_type_alias, @@ -1846,6 +1847,7 @@ symbols! { rustc_abi, // FIXME(#82232, #143834): temporary name to mitigate `#[align]` nameres ambiguity rustc_align, + rustc_align_static, rustc_allocator, rustc_allocator_zeroed, rustc_allocator_zeroed_variant, @@ -2097,6 +2099,7 @@ symbols! { staged_api, start, state, + static_align, static_in_const, static_nobundle, static_recursion, @@ -2868,11 +2871,20 @@ impl Interner { let byte_strs = FxIndexSet::from_iter( init.iter().copied().chain(extra.iter().copied()).map(|str| str.as_bytes()), ); - assert_eq!( - byte_strs.len(), - init.len() + extra.len(), - "duplicate symbols in the rustc symbol list and the extra symbols added by the driver", - ); + + // The order in which duplicates are reported is irrelevant. + #[expect(rustc::potential_query_instability)] + if byte_strs.len() != init.len() + extra.len() { + panic!( + "duplicate symbols in the rustc symbol list and the extra symbols added by the driver: {:?}", + FxHashSet::intersection( + &init.iter().copied().collect(), + &extra.iter().copied().collect(), + ) + .collect::<Vec<_>>() + ) + } + Interner(Lock::new(InternerInner { arena: Default::default(), byte_strs })) } |
