diff --git a/Cargo.lock b/Cargo.lock index 53cff99b4a199..6b5491fb754de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3853,8 +3853,6 @@ dependencies = [ "icu_list", "icu_locale", "intl-memoizer", - "rustc_ast", - "rustc_ast_pretty", "rustc_baked_icu_data", "rustc_data_structures", "rustc_macros", @@ -4186,7 +4184,6 @@ dependencies = [ name = "rustc_lint_defs" version = "0.0.0" dependencies = [ - "rustc_ast", "rustc_data_structures", "rustc_error_messages", "rustc_hir_id", diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 7dee8fbd3b9f0..9de25c4cec405 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -261,6 +261,7 @@ impl StableOrd for ExternAbi { rustc_error_messages::into_diag_arg_using_display!(ExternAbi); #[cfg(feature = "nightly")] +#[derive(Debug)] pub enum CVariadicStatus { NotSupported, Stable, diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 46d7beae8fe58..e8df8ce6e6dc3 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::msg; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{Span, sym}; use rustc_target::asm; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4e1b46d568099..86eb721ad284c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1693,7 +1693,7 @@ impl<'hir> LoweringContext<'_, 'hir> { && !self.tcx.features().coroutines() && !self.tcx.features().gen_blocks() { - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( &self.tcx.sess, sym::yield_expr, span, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6ca6bf3e1f6dc..49790c2da6de4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -62,7 +62,7 @@ use rustc_macros::extension; use rustc_middle::hir::{self as mid_hir}; use rustc_middle::span_bug; use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt}; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::errors::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::SmallVec; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 49c5f060e2a1e..ef60dc6fc4f1c 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, PartialRes, PerNS, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; use rustc_middle::{span_bug, ty}; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::errors::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::smallvec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index d185cc9163eb6..326576bb14881 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -3,7 +3,7 @@ use std::fmt; use rustc_abi::ExternAbi; use rustc_feature::Features; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 770189d8c7999..d9f03342e1047 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -30,11 +30,11 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DiagCtxtHandle, Diagnostic, LintBuffer}; use rustc_feature::Features; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES, }; -use rustc_session::parse::feature_err; use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; @@ -762,12 +762,23 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { - if !self.sess.target.supports_c_variadic_definitions() { - self.dcx().emit_err(errors::CVariadicNotSupported { - variadic_span: variadic_param.span, - target: &*self.sess.target.llvm_target, - }); - return; + match self.sess.target.supports_c_variadic_definitions() { + CVariadicStatus::NotSupported => { + self.dcx().emit_err(errors::CVariadicNotSupported { + variadic_span: variadic_param.span, + target: &*self.sess.target.llvm_target, + }); + return; + } + CVariadicStatus::Unstable { feature } if !self.features.enabled(feature) => { + let msg = + format!("C-variadic function definitions on this target are unstable"); + feature_err(&self.sess, feature, variadic_param.span, msg).emit(); + return; + } + CVariadicStatus::Unstable { .. } | CVariadicStatus::Stable => { + /* fall through */ + } } match sig.header.ext { @@ -1117,8 +1128,8 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara dcx.emit_err(errors::OutOfOrderParams { spans: spans.clone(), sugg_span: span, - param_ord, - max_param, + param_ord: param_ord.to_string(), + max_param: max_param.to_string(), ordered_params: &ordered_params, }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index b3a22c0c99549..a6b75cb70a548 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -1,7 +1,6 @@ //! Errors emitted by ast_passes. use rustc_abi::ExternAbi; -use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -632,8 +631,8 @@ pub(crate) struct OutOfOrderParams<'a> { applicability = "machine-applicable" )] pub sugg_span: Span, - pub param_ord: &'a ParamKindOrd, - pub max_param: &'a ParamKindOrd, + pub param_ord: String, + pub max_param: String, pub ordered_params: &'a str, } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5831636a81b2c..2b08906a77434 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -6,7 +6,7 @@ use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Feat use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; use rustc_session::Session; -use rustc_session::parse::{feature_err, feature_warn}; +use rustc_session::errors::{feature_err, feature_warn}; use rustc_span::{Span, Spanned, Symbol, sym}; use thin_vec::ThinVec; @@ -510,6 +510,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental"); gate_all!(unsafe_binders, "unsafe binder types are experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); + gate_all!(view_types, "view types are experimental"); gate_all!(where_clause_attrs, "attributes in `where` clause are unstable"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 80a1d9aa5defd..4cc07ceaf231f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -13,8 +13,9 @@ use rustc_parse::parser::{ForceCollect, Parser, Recovery}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; use rustc_session::config::ExpectedValues; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::parse::{ParseSess, feature_err}; +use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a20813406b024..a6cf25330b557 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,5 +1,5 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edition::Edition::Edition2024; use super::prelude::*; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 76fa2aed5c79c..070b0e385b024 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_hir::attrs::{CrateType, WindowsSubsystemKind}; use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES; use rustc_span::Symbol; @@ -61,12 +60,8 @@ impl CombineAttributeParser for CrateTypeParser { let span = n.value_span; cx.emit_lint( UNKNOWN_CRATE_TYPES, - move |dcx, level| { - UnknownCrateTypes { - sugg: candidate - .map(|s| UnknownCrateTypesSuggestion { span, snippet: s }), - } - .into_diag(dcx, level) + UnknownCrateTypes { + sugg: candidate.map(|s| UnknownCrateTypesSuggestion { span, snippet: s }), }, span, ); diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs index e7adef010aa74..4631639da5ff4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/do_not_recommend.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_feature::{AttributeTemplate, template}; use rustc_hir::Target; use rustc_hir::attrs::AttributeKind; @@ -26,7 +25,7 @@ impl SingleAttributeParser for DoNotRecommendParser { if !matches!(args, ArgParser::NoArgs) { cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - |dcx, level| crate::errors::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level), + crate::errors::DoNotRecommendDoesNotExpectArgs, attr_span, ); } @@ -35,9 +34,7 @@ impl SingleAttributeParser for DoNotRecommendParser { let target_span = cx.target_span; cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - IncorrectDoNotRecommendLocation { target_span }.into_diag(dcx, level) - }, + IncorrectDoNotRecommendLocation { target_span }, attr_span, ); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs index 375eaba2844bb..816d51a6ba395 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use rustc_errors::{Diagnostic, E0232}; +use rustc_errors::E0232; use rustc_hir::AttrPath; use rustc_hir::attrs::diagnostic::{ Directive, FilterFormatString, Flag, FormatArg, FormatString, LitOrArg, Name, NameValue, @@ -142,10 +142,7 @@ fn merge( let first_span = *first_span; cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - IgnoredDiagnosticOption { first_span, later_span, option_name } - .into_diag(dcx, level) - }, + IgnoredDiagnosticOption { first_span, later_span, option_name }, later_span, ); } @@ -169,19 +166,16 @@ fn parse_list<'p>( // if the user used non-metaitem syntax. See `ArgParser::from_attr_args`. cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| NonMetaItemDiagnosticAttribute.into_diag(dcx, level), + NonMetaItemDiagnosticAttribute, list.span, ); } ArgParser::NoArgs => { cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - MissingOptionsForDiagnosticAttribute { - attribute: mode.as_str(), - options: mode.expected_options(), - } - .into_diag(dcx, level) + MissingOptionsForDiagnosticAttribute { + attribute: mode.as_str(), + options: mode.expected_options(), }, span, ); @@ -189,13 +183,10 @@ fn parse_list<'p>( ArgParser::NameValue(_) => { cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - MalFormedDiagnosticAttributeLint { - attribute: mode.as_str(), - options: mode.allowed_options(), - span, - } - .into_diag(dcx, level) + MalFormedDiagnosticAttributeLint { + attribute: mode.as_str(), + options: mode.allowed_options(), + span, }, span, ); @@ -223,13 +214,10 @@ fn parse_directive_items<'p>( macro malformed() {{ cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - MalFormedDiagnosticAttributeLint { - attribute: mode.as_str(), - options: mode.allowed_options(), - span, - } - .into_diag(dcx, level) + MalFormedDiagnosticAttributeLint { + attribute: mode.as_str(), + options: mode.allowed_options(), + span, }, span, ); @@ -251,11 +239,11 @@ fn parse_directive_items<'p>( let first_span = $($first_span)*; cx.emit_lint( MALFORMED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| IgnoredDiagnosticOption { + IgnoredDiagnosticOption { first_span, later_span: span, option_name: $name, - }.into_diag(dcx, level), + }, span, ); }} @@ -285,11 +273,7 @@ fn parse_directive_items<'p>( | FormatWarning::PositionalArgument { span } | FormatWarning::IndexedArgument { span } | FormatWarning::DisallowedPlaceholder { span, .. }) = warning; - cx.emit_lint( - MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, - move |dcx, level| warning.into_diag(dcx, level), - span, - ); + cx.emit_lint(MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, warning, span); } f @@ -297,13 +281,10 @@ fn parse_directive_items<'p>( Err(e) => { cx.emit_lint( MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, - move |dcx, level| { - WrappedParserError { - description: &e.description, - label: &e.label, - span: slice_span(input.span, e.span.clone(), is_snippet), - } - .into_diag(dcx, level) + WrappedParserError { + description: e.description, + label: e.label, + span: slice_span(input.span, e.span.clone(), is_snippet), }, input.span, ); diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs index e6c66b597ce08..e783e49ef1e83 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_hir::attrs::diagnostic::Directive; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; @@ -30,9 +29,7 @@ impl AttributeParser for OnConstParser { let target_span = cx.target_span; cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - DiagnosticOnConstOnlyForTraitImpls { target_span }.into_diag(dcx, level) - }, + DiagnosticOnConstOnlyForTraitImpls { target_span }, span, ); return; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs index d4ef92fc9a548..260815b4718c1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_feature::template; use rustc_hir::attrs::AttributeKind; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; @@ -28,11 +27,7 @@ impl OnMoveParser { self.span = Some(span); if !matches!(cx.target, Target::Enum | Target::Struct | Target::Union) { - cx.emit_lint( - MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| DiagnosticOnMoveOnlyForAdt.into_diag(dcx, level), - span, - ); + cx.emit_lint(MISPLACED_DIAGNOSTIC_ATTRIBUTES, DiagnosticOnMoveOnlyForAdt, span); return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs index b60d732bc6bf3..e4d01b006c226 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_hir::attrs::diagnostic::Directive; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; @@ -20,7 +19,7 @@ impl OnUnimplementedParser { if !matches!(cx.target, Target::Trait) { cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| DiagnosticOnUnimplementedOnlyForTraits.into_diag(dcx, level), + DiagnosticOnUnimplementedOnlyForTraits, span, ); return; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index 0a9aaaaa1893e..7d77497f04294 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_hir::attrs::diagnostic::Directive; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; @@ -32,9 +31,7 @@ impl OnUnknownParser { let target_span = cx.target_span; cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| { - DiagnosticOnUnknownOnlyForImports { target_span }.into_diag(dcx, level) - }, + DiagnosticOnUnknownOnlyForImports { target_span }, span, ); return; diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs index 3f1474ba4543e..923e5ca2b96df 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unmatch_args.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_hir::attrs::diagnostic::Directive; use rustc_session::lint::builtin::MISPLACED_DIAGNOSTIC_ATTRIBUTES; @@ -27,7 +26,7 @@ impl AttributeParser for OnUnmatchArgsParser { if !matches!(cx.target, Target::MacroDef) { cx.emit_lint( MISPLACED_DIAGNOSTIC_ATTRIBUTES, - move |dcx, level| DiagnosticOnUnmatchArgsOnlyForMacros.into_diag(dcx, level), + DiagnosticOnUnmatchArgsOnlyForMacros, span, ); return; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index c0b90c2c6d97f..63c86f3ee9ef6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,11 +1,11 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; -use rustc_errors::{Applicability, Diagnostic, msg}; +use rustc_errors::{Applicability, msg}; use rustc_feature::template; use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; @@ -66,7 +66,7 @@ fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_>, span: Span) -> bool { if cx.shared.target != Target::Crate { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| AttrCrateLevelOnly.into_diag(dcx, level), + AttrCrateLevelOnly, span, ); return false; @@ -76,20 +76,12 @@ fn check_attr_crate_level(cx: &mut AcceptContext<'_, '_>, span: Span) -> bool { // FIXME: To be removed once merged and replace with `cx.expected_name_value(span, _name)`. fn expected_name_value(cx: &mut AcceptContext<'_, '_>, span: Span, _name: Option) { - cx.emit_lint( - rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| ExpectedNameValue.into_diag(dcx, level), - span, - ); + cx.emit_lint(rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, ExpectedNameValue, span); } // FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead. fn expected_no_args(cx: &mut AcceptContext<'_, '_>, span: Span) { - cx.emit_lint( - rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| ExpectedNoArgs.into_diag(dcx, level), - span, - ); + cx.emit_lint(rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, ExpectedNoArgs, span); } // FIXME: remove this method once merged and use `cx.expected_no_args(span)` instead. @@ -99,11 +91,7 @@ fn expected_string_literal( span: Span, _actual_literal: Option<&MetaItemLit>, ) { - cx.emit_lint( - rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| MalformedDoc.into_diag(dcx, level), - span, - ); + cx.emit_lint(rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, MalformedDoc, span); } fn parse_keyword_and_attribute( @@ -171,13 +159,10 @@ impl DocParser { let unused_span = path.span(); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - rustc_errors::lints::UnusedDuplicate { - this: unused_span, - other: used_span, - warning: true, - } - .into_diag(dcx, level) + rustc_errors::lints::UnusedDuplicate { + this: unused_span, + other: used_span, + warning: true, }, unused_span, ); @@ -197,7 +182,7 @@ impl DocParser { let span = cx.attr_span; cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| MalformedDoc.into_diag(dcx, level), + MalformedDoc, span, ); return; @@ -211,14 +196,14 @@ impl DocParser { Some(name) => { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocTestUnknown { name }.into_diag(dcx, level), + DocTestUnknown { name }, path.span(), ); } None => { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| DocTestLiteral.into_diag(dcx, level), + DocTestLiteral, path.span(), ); } @@ -250,7 +235,7 @@ impl DocParser { if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { cx.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| DocAliasDuplicated { first_definition }.into_diag(dcx, level), + DocAliasDuplicated { first_definition }, span, ); } @@ -338,7 +323,7 @@ impl DocParser { let MetaItemOrLitParser::MetaItemParser(item) = meta else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), + DocAutoCfgExpectsHideOrShow, meta.span(), ); continue; @@ -349,7 +334,7 @@ impl DocParser { _ => { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), + DocAutoCfgExpectsHideOrShow, item.span(), ); continue; @@ -358,9 +343,7 @@ impl DocParser { let ArgParser::List(list) = item.args() else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level) - }, + DocAutoCfgHideShowExpectsList { attr_name }, item.span(), ); continue; @@ -372,10 +355,7 @@ impl DocParser { let MetaItemOrLitParser::MetaItemParser(sub_item) = item else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - DocAutoCfgHideShowUnexpectedItem { attr_name } - .into_diag(dcx, level) - }, + DocAutoCfgHideShowUnexpectedItem { attr_name }, item.span(), ); continue; @@ -388,7 +368,7 @@ impl DocParser { // cx.expected_identifier(sub_item.path().span()); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| MalformedDoc.into_diag(dcx, level), + MalformedDoc, sub_item.path().span(), ); continue; @@ -415,10 +395,7 @@ impl DocParser { _ => { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - DocAutoCfgHideShowUnexpectedItem { attr_name } - .into_diag(dcx, level) - }, + DocAutoCfgHideShowUnexpectedItem { attr_name }, sub_item.span(), ); continue; @@ -433,7 +410,7 @@ impl DocParser { else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocAutoCfgWrongLiteral.into_diag(dcx, level), + DocAutoCfgWrongLiteral, nv.value_span, ); return; @@ -573,7 +550,7 @@ impl DocParser { let Some(list) = args.as_list() else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| DocTestTakesList.into_diag(dcx, level), + DocTestTakesList, args.span().unwrap_or(path.span()), ); return; @@ -590,7 +567,7 @@ impl DocParser { // cx.unexpected_literal(lit.span); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - |dcx, level| MalformedDoc.into_diag(dcx, level), + MalformedDoc, lit.span, ); } @@ -601,7 +578,7 @@ impl DocParser { let span = path.span(); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level), + DocUnknownSpotlight { sugg_span: span }, span, ); } @@ -614,14 +591,7 @@ impl DocParser { let span = path.span(); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - DocUnknownInclude { - inner, - value, - sugg: (span, Applicability::MaybeIncorrect), - } - .into_diag(dcx, level) - }, + DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) }, span, ); } @@ -629,9 +599,7 @@ impl DocParser { let span = path.span(); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - DocUnknownPasses { name, note_span: span }.into_diag(dcx, level) - }, + DocUnknownPasses { name, note_span: span }, span, ); } @@ -639,14 +607,14 @@ impl DocParser { let span = path.span(); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocUnknownPlugins { label_span: span }.into_diag(dcx, level), + DocUnknownPlugins { label_span: span }, span, ); } Some(name) => { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level), + DocUnknownAny { name }, path.span(), ); } @@ -656,7 +624,7 @@ impl DocParser { let name = Symbol::intern(&full_name); cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| DocUnknownAny { name }.into_diag(dcx, level), + DocUnknownAny { name }, path.span(), ); } @@ -670,9 +638,7 @@ impl DocParser { let span = cx.attr_span; cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - move |dcx, level| { - IllFormedAttributeInput::new(&suggestions, None, None).into_diag(dcx, level) - }, + IllFormedAttributeInput::new(&suggestions, None, None), span, ); } diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 0ca059bf4030b..039977c74c1bb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -3,8 +3,8 @@ use rustc_feature::Features; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::*; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition::Edition2024; use rustc_span::kw; use rustc_target::spec::{Arch, BinaryFormat}; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 00af9bd38e60c..88253041ed6e0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,4 +1,3 @@ -use rustc_errors::Diagnostic; use rustc_session::lint::builtin::AMBIGUOUS_DERIVE_HELPERS; use super::prelude::*; @@ -124,7 +123,7 @@ fn parse_derive_like( if rustc_feature::is_builtin_attr_name(ident.name) { cx.emit_lint( AMBIGUOUS_DERIVE_HELPERS, - |dcx, level| crate::errors::AmbiguousDeriveHelpers.into_diag(dcx, level), + crate::errors::AmbiguousDeriveHelpers, ident.span, ); } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 02a7aac9659f2..9c82e6208c24c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -371,23 +371,21 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing /// must be delayed until after HIR is built. This method will take care of the details of /// that. - pub(crate) fn emit_lint< - F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static, - >( + pub(crate) fn emit_lint( &mut self, lint: &'static Lint, - callback: F, + diagnostic: impl for<'x> Diagnostic<'x, ()> + DynSend + DynSync + 'static, span: impl Into, ) { self.emit_lint_inner( lint, - EmitAttribute(Box::new(move |dcx, level, _| callback(dcx, level))), + EmitAttribute(Box::new(move |dcx, level, _| diagnostic.into_diag(dcx, level))), span, ); } pub(crate) fn emit_lint_with_sess< - F: for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()> + F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()> + DynSend + DynSync + 'static, @@ -418,13 +416,10 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) { self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| { - rustc_errors::lints::UnusedDuplicate { - this: unused_span, - other: used_span, - warning: false, - } - .into_diag(dcx, level) + rustc_errors::lints::UnusedDuplicate { + this: unused_span, + other: used_span, + warning: false, }, unused_span, ) @@ -437,13 +432,10 @@ impl<'f, 'sess: 'f> SharedContext<'f, 'sess> { ) { self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| { - rustc_errors::lints::UnusedDuplicate { - this: unused_span, - other: used_span, - warning: true, - } - .into_diag(dcx, level) + rustc_errors::lints::UnusedDuplicate { + this: unused_span, + other: used_span, + warning: true, }, unused_span, ) @@ -967,14 +959,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> { let valid_without_list = self.template.word; self.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| { - crate::errors::EmptyAttributeList { - attr_span: span, - attr_path: &attr_path, - valid_without_list, - } - .into_diag(dcx, level) - }, + crate::errors::EmptyAttributeList { attr_span: span, attr_path, valid_without_list }, span, ); } @@ -991,10 +976,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> { let span = self.attr_span; self.emit_lint( lint, - move |dcx, level| { - crate::errors::IllFormedAttributeInput::new(&suggestions, None, help.as_deref()) - .into_diag(dcx, level) - }, + crate::errors::IllFormedAttributeInput::new(&suggestions, None, help.as_deref()), span, ); } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 85304241660be..d2c9c1b1eb807 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -118,7 +118,7 @@ struct IllFormedAttributeInputHelp { *[other] using `{$attr_path}` with an empty list has no effect }" )] -pub(crate) struct EmptyAttributeList<'a> { +pub(crate) struct EmptyAttributeList { #[suggestion( "{$valid_without_list -> [true] remove these parentheses @@ -128,7 +128,7 @@ pub(crate) struct EmptyAttributeList<'a> { applicability = "machine-applicable" )] pub attr_span: Span, - pub attr_path: &'a str, + pub attr_path: String, pub valid_without_list: bool, } @@ -159,8 +159,8 @@ pub(crate) struct InvalidTargetLint { *[other] the `#![{$name}]` attribute can only be used at the crate root }" )] -pub(crate) struct InvalidAttrStyle<'a> { - pub name: &'a str, +pub(crate) struct InvalidAttrStyle { + pub name: String, pub is_used_as_inner: bool, #[note("this attribute does not have an `!`, which means it is applied to this {$target}")] pub target_span: Option, @@ -359,11 +359,11 @@ pub(crate) struct MalFormedDiagnosticAttributeLint { #[derive(Diagnostic)] #[diag("{$description}")] -pub(crate) struct WrappedParserError<'a> { - pub description: &'a str, +pub(crate) struct WrappedParserError { + pub description: String, #[label("{$label}")] pub span: Span, - pub label: &'a str, + pub label: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index f4506d8d5fedc..567cdc7701eae 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -23,7 +23,7 @@ use crate::{OmitDoc, ShouldEmit}; pub struct EmitAttribute( pub Box< - dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()> + dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &Session) -> Diag<'a, ()> + DynSend + DynSync + 'static, diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index f0305c320f8f0..d05f1baf63dad 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -142,9 +142,9 @@ impl<'sess> AttributeParser<'sess> { }; let attr_span = cx.attr_span; - cx.emit_lint( + cx.emit_lint_with_sess( lint, - move |dcx, level| { + move |dcx, level, _| { InvalidTargetLint { name: name.to_string(), target: target.plural_name(), @@ -188,14 +188,11 @@ impl<'sess> AttributeParser<'sess> { cx.emit_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| { - crate::errors::InvalidAttrStyle { - name: &name, - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target: target.name(), - } - .into_diag(dcx, level) + crate::errors::InvalidAttrStyle { + name, + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target: target.name(), }, attr_span, ); diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index f60113dbfc9bc..d9af43fcd1c3d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -9,6 +9,7 @@ use std::env::VarError; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ExprKind, GenericArg, Mutability}; +use rustc_ast_pretty::pprust; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::edit_distance::edit_distance; use rustc_span::{Ident, Span, Symbol, kw, sym}; @@ -158,13 +159,13 @@ pub(crate) fn expand_env<'cx>( cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, - var_expr: &var_expr, + var_expr: pprust::expr_to_string(&var_expr), }) } else { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { span, var: *symbol, - var_expr: &var_expr, + var_expr: pprust::expr_to_string(&var_expr), }) } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ad641beb87d98..c64d6871269a6 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -553,7 +553,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessag } #[derive(Diagnostic)] -pub(crate) enum EnvNotDefined<'a> { +pub(crate) enum EnvNotDefined { #[diag("environment variable `{$var}` not defined at compile time")] #[help("`{$var}` may not be available for the current Cargo target")] #[help( @@ -563,7 +563,7 @@ pub(crate) enum EnvNotDefined<'a> { #[primary_span] span: Span, var: Symbol, - var_expr: &'a rustc_ast::Expr, + var_expr: String, }, #[diag("environment variable `{$var}` not defined at compile time")] #[help("there is a similar Cargo environment variable: `{$suggested_var}`")] @@ -579,7 +579,7 @@ pub(crate) enum EnvNotDefined<'a> { #[primary_span] span: Span, var: Symbol, - var_expr: &'a rustc_ast::Expr, + var_expr: String, }, } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index be4bde5145d8c..33f0f6fc2f809 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1659,6 +1659,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } + fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { + unimplemented!(); + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index bdb8316f3965d..a32592b45e5ea 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -828,7 +828,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return_error!(InvalidMonomorphization::FloatingPointVector { span, name, - f_ty: *f, + f_ty: f.name_str().to_string(), in_ty }); } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index d50968bad2501..4be25b3fb0934 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -430,8 +430,8 @@ impl WriteBackendMethods for GccCodegenBackend { } fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, _tm_factory: TargetMachineFactoryFn, // FIXME(bjorn3): Limit LTO exports to these symbols @@ -439,7 +439,7 @@ impl WriteBackendMethods for GccCodegenBackend { each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> CompiledModule { - back::lto::run_fat(cgcx, prof, shared_emitter, each_linked_rlib_for_lto, modules) + back::lto::run_fat(cgcx, &sess.prof, shared_emitter, each_linked_rlib_for_lto, modules) } fn run_thin_lto( diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index a61ec362e800d..7e5f71209fbab 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1289,6 +1289,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ret } + fn get_funclet_cleanuppad(&self, funclet: &Funclet<'ll>) -> &'ll Value { + funclet.cleanuppad() + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 65c70c754918d..575e37d0b171d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -133,8 +133,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { back::write::target_machine_factory(sess, optlvl, target_features) } fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], @@ -143,7 +143,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> CompiledModule { let mut module = back::lto::run_fat( cgcx, - prof, + &sess.prof, shared_emitter, tm_factory, exported_symbols_for_lto, @@ -153,9 +153,9 @@ impl WriteBackendMethods for LlvmCodegenBackend { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, prof, dcx, &mut module, false); + back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &mut module, false); - back::write::codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) + back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config) } fn run_thin_lto( cgcx: &CodegenContext, diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index cfdd47b3a8c8c..09d3a5a3f040f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; +use rustc_abi::{Align, BackendRepr, CVariadicStatus, Endian, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; @@ -1038,6 +1038,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( assert!(!bx.layout_of(target_ty).is_zst()); let target = &bx.cx.tcx.sess.target; + let stability = target.supports_c_variadic_definitions(); + match target.arch { Arch::X86 => emit_ptr_va_arg( bx, @@ -1094,6 +1096,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( ForceRightAdjust::Yes, ), Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); // FIXME: clang manually adjusts the alignment for this ABI. It notes: // // > To be compatible with GCC's behaviors, we force arguments with @@ -1215,10 +1218,15 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( Arch::SpirV => bug!("spirv does not support c-variadic functions"), Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Clang uses the LLVM implementation for these architectures. bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } + Arch::Other(ref arch) => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Just to be safe we error out explicitly here, instead of crossing our fingers that // the default LLVM implementation has the correct behavior for this target. bug!("c-variadic functions are not currently implemented for custom target {arch}") diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index eb908e19be54e..76aecb3b9e54e 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -736,13 +736,15 @@ impl<'a> Linker for GccLinker<'a> { fn enable_profiling(&mut self) { // This flag is also used when linking to choose target specific // libraries needed to enable profiling. - self.cc_arg("-pg"); - // On windows-gnu targets, libgmon also needs to be linked, and this - // requires readding libraries to satisfy its dependencies. - if self.sess.target.is_like_windows { - self.cc_arg("-lgmon"); - self.cc_arg("-lkernel32"); - self.cc_arg("-lmsvcrt"); + if !self.is_ld { + self.cc_arg("-pg"); + // On windows-gnu targets, libgmon also needs to be linked, and this + // requires readding libraries to satisfy its dependencies. + if self.sess.target.is_like_windows { + self.cc_arg("-lgmon"); + self.cc_arg("-lkernel32"); + self.cc_arg("-lmsvcrt"); + } } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index ff91a08de4de6..c48e8a58b6964 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -961,15 +961,15 @@ fn execute_copy_from_cache_work_item( } fn do_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], needs_fat_lto: Vec>, ) -> CompiledModule { - let _timer = prof.verbose_generic_activity("LLVM_fatlto"); + let _timer = sess.prof.verbose_generic_activity("LLVM_fatlto"); let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); @@ -977,8 +977,8 @@ fn do_fat_lto( check_lto_allowed(&cgcx, dcx); B::optimize_and_codegen_fat_lto( + sess, cgcx, - prof, &shared_emitter, tm_factory, exported_symbols_for_lto, @@ -2177,8 +2177,8 @@ impl OngoingCodegen { CompiledModules { modules: vec![do_fat_lto( + sess, &cgcx, - &sess.prof, shared_emitter, tm_factory, &exported_symbols_for_lto, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 820436bb6a265..3e19f7f95470f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -12,8 +12,8 @@ use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::mono::Visibility; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; +use rustc_session::errors::feature_err; use rustc_session::lint; -use rustc_session::parse::feature_err; use rustc_span::{Span, sym}; use rustc_target::spec::Os; diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index c3afcd6f40333..280cbb590781d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -13,8 +13,8 @@ use rustc_errors::{ Level, msg, }; use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; -use rustc_middle::ty::{FloatTy, Ty}; use rustc_span::{Span, Symbol}; use crate::assert_module_sources::CguReuse; @@ -748,7 +748,7 @@ pub enum InvalidMonomorphization<'tcx> { #[primary_span] span: Span, name: Symbol, - f_ty: FloatTy, + f_ty: String, in_ty: Ty<'tcx>, }, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 06c81662d6018..2967db9df787c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -214,19 +214,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) { + if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) { + // For wasm, we need to generate a nested `cleanuppad within %outer_pad` + // to catch exceptions during cleanup and call `panic_in_cleanup`. + Some(fx.terminate_block(reason, Some(self.bb))) + } else if fx.mir[self.bb].is_cleanup + && base::wants_new_eh_instructions(fx.cx.tcx().sess) + { // MSVC SEH will abort automatically if an exception tries to // propagate out from cleanup. - - // FIXME(@mirkootter): For wasm, we currently do not support terminate during - // cleanup, because this requires a few more changes: The current code - // caches the `terminate_block` for each function; funclet based code - however - - // requires a different terminate_block for each funclet - // Until this is implemented, we just do not unwind inside cleanup blocks - None } else { - Some(fx.terminate_block(reason)) + Some(fx.terminate_block(reason, None)) } } }; @@ -238,7 +237,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -309,7 +308,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { ) -> MergingSucc { let unwind_target = match unwind { mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)), + mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason, None)), mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, }; @@ -317,7 +316,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { assert!(unwind_target.is_none()); let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -334,7 +333,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { MergingSucc::False } else if let Some(cleanup) = unwind_target { let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -1906,8 +1905,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } - fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block + fn terminate_block( + &mut self, + reason: UnwindTerminateReason, + outer_catchpad_bb: Option, + ) -> Bx::BasicBlock { + // mb_funclet_bb should be present if and only if the target is wasm and + // we're terminating because of an unwind in a cleanup block. In that + // case we have nested funclets and the inner catch_switch needs to know + // what outer catch_pad it is contained in. + debug_assert!( + outer_catchpad_bb.is_some() + == (base::wants_wasm_eh(self.cx.tcx().sess) + && reason == UnwindTerminateReason::InCleanup) + ); + + // When we aren't in a wasm InCleanup block, there's only one terminate + // block needed so we cache at START_BLOCK index. + let mut cache_bb = mir::START_BLOCK; + // In wasm eh InCleanup, use the outer funclet's cleanup BB as the cache + // key. + if let Some(outer_bb) = outer_catchpad_bb { + let cleanup_kinds = + self.cleanup_kinds.as_ref().expect("cleanup_kinds required for funclets"); + cache_bb = cleanup_kinds[outer_bb] + .funclet_bb(outer_bb) + .expect("funclet_bb should be in a funclet"); + + // Ensure the outer funclet is created first + if self.funclets[cache_bb].is_none() { + self.landing_pad_for(cache_bb); + } + } + if let Some((cached_bb, cached_reason)) = self.terminate_blocks[cache_bb] && reason == cached_reason { return cached_bb; @@ -1945,12 +1975,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // cp_terminate: // %cp = catchpad within %cs [null, i32 64, null] // ... + // + // By contrast, on WebAssembly targets, we specifically _do_ want to + // catch foreign exceptions. The situation with MSVC is a + // regrettable hack which we don't want to extend to other targets + // unless necessary. For WebAssembly, to generate catch(...) and + // catch only C++ exception instead of generating a catch_all, we + // need to call the intrinsics @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector in the catch pad. Since we don't do + // this, we generate a catch_all. We originally got this behavior + // by accident but it luckily matches our intention. llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate"); - let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); let mut cs_bx = Bx::build(self.cx, llbb); - let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); + + // For wasm InCleanup blocks, our catch_switch is nested within the + // outer catchpad, so we need to provide it as the parent value to + // catch_switch. + let mut outer_cleanuppad = None; + if outer_catchpad_bb.is_some() { + // Get the outer funclet's catchpad + let outer_funclet = self.funclets[cache_bb] + .as_ref() + .expect("landing_pad_for didn't create funclet"); + outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet)); + } + let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); + let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]); + drop(cs_bx); bx = Bx::build(self.cx, cp_llbb); let null = @@ -1971,13 +2024,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { // Specifying more arguments than necessary usually doesn't // hurt, but the `WasmEHPrepare` LLVM pass does not recognize - // anything other than a single `null` as a `catch (...)` block, + // anything other than a single `null` as a `catch_all` block, // leading to problems down the line during instruction // selection. &[null] as &[_] }; funclet = Some(bx.catch_pad(cs, args)); + // On wasm, if we wanted to generate a catch(...) and only catch C++ + // exceptions, we'd call @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector selectors here. We want a catch_all so + // we leave them out. This is intentionally diverging from the MSVC + // behavior. } else { llbb = Bx::append_block(self.cx, self.llfn, "terminate"); bx = Bx::build(self.cx, llbb); @@ -2003,7 +2061,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.unreachable(); - self.terminate_block = Some((llbb, reason)); + self.terminate_blocks[cache_bb] = Some((llbb, reason)); llbb } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index f4a5e8baa2a5f..aa144558211ef 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -148,8 +148,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return Ok(()); } + // va_end uses the fallback body (a no-op). sym::va_start => bx.va_start(args[0].immediate()), - sym::va_end => bx.va_end(args[0].immediate()), + sym::size_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 93da12107bab0..5c14d6f2c0930 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -90,8 +90,11 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached unreachable block unreachable_block: Option, - /// Cached terminate upon unwinding block and its reason - terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, + /// Cached terminate upon unwinding block and its reason. For non-wasm + /// targets, there is at most one such block per function, stored at index + /// `START_BLOCK`. For wasm targets, each funclet needs its own terminate + /// block, indexed by the cleanup block that is the funclet's head. + terminate_blocks: IndexVec>, /// A bool flag for each basic block indicating whether it is a cold block. /// A cold block is a block that is unlikely to be executed at runtime. @@ -227,7 +230,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( personality_slot: None, cached_llbbs, unreachable_block: None, - terminate_block: None, + terminate_blocks: IndexVec::from_elem(None, &mir.basic_blocks), cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 4b1b0866f2eb9..b7d09d69aaecd 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -7,8 +7,8 @@ use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; -use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, edit_distance, sym}; use rustc_target::spec::{Arch, SanitizerSet}; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index c222aef4574bf..5092f28a33f7b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -552,12 +552,12 @@ pub trait BuilderMethods<'a, 'tcx>: fn set_personality_fn(&mut self, personality: Self::Function); - // These are used by everyone except msvc + // These are used by everyone except msvc and wasm EH fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); - // These are used only by msvc + // These are used by msvc and wasm EH fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option); fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; @@ -567,6 +567,7 @@ pub trait BuilderMethods<'a, 'tcx>: unwind: Option, handlers: &[Self::BasicBlock], ) -> Self::Value; + fn get_funclet_cleanuppad(&self, funclet: &Self::Funclet) -> Self::Value; fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index cca6db78e381e..9b8bf138e7a14 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -30,8 +30,8 @@ pub trait WriteBackendMethods: Clone + 'static { /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d64cf8e032935..c776fa69ba5c1 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, AssocContainer, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, suggest_constraining_type_param, }; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::errors::add_feature_diagnostics; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::traits::call_kind::{ CallDesugaringKind, CallKind, call_kind, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 6c9cd2e608ae1..7b2983620d420 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -216,14 +216,11 @@ impl std::fmt::Display for ImmTy<'_, Prov> { ty::tls::with(|tcx| { match self.imm { Immediate::Scalar(s) => { - if let Some(ty) = tcx.lift(self.layout.ty) { - let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { - print_scalar(p, s, ty) - })?; - f.write_str(&s)?; - return Ok(()); - } - write!(f, "{:x}: {}", s, self.layout.ty) + let ty = tcx.lift(self.layout.ty); + let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { + print_scalar(p, s, ty) + })?; + f.write_str(&s) } Immediate::ScalarPair(a, b) => { // FIXME(oli-obk): at least print tuples and slices nicely diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index f280aaff11260..687aff5e9229a 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -9,8 +9,6 @@ fluent-bundle = "0.16" icu_list = { version = "2.0", default-features = false, features = ["alloc"] } icu_locale = { version = "2.0", default-features = false } intl-memoizer = "0.5.1" -rustc_ast = { path = "../rustc_ast" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_baked_icu_data = { path = "../rustc_baked_icu_data" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_error_messages/src/diagnostic_impls.rs b/compiler/rustc_error_messages/src/diagnostic_impls.rs index 3b664cce5776f..38b086eaa80d3 100644 --- a/compiler/rustc_error_messages/src/diagnostic_impls.rs +++ b/compiler/rustc_error_messages/src/diagnostic_impls.rs @@ -5,8 +5,6 @@ use std::num::ParseIntError; use std::path::{Path, PathBuf}; use std::process::ExitStatus; -use rustc_ast as ast; -use rustc_ast_pretty::pprust; use rustc_span::edition::Edition; use crate::{DiagArgValue, IntoDiagArg}; @@ -69,7 +67,6 @@ macro_rules! into_diag_arg_for_number { } into_diag_arg_using_display!( - ast::ParamKindOrd, std::io::Error, Box, std::num::NonZero, @@ -142,30 +139,6 @@ impl IntoDiagArg for PathBuf { } } -impl IntoDiagArg for ast::Expr { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self))) - } -} - -impl IntoDiagArg for ast::Path { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self))) - } -} - -impl IntoDiagArg for ast::token::Token { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(pprust::token_to_string(&self)) - } -} - -impl IntoDiagArg for ast::token::TokenKind { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(pprust::token_kind_to_string(&self)) - } -} - impl IntoDiagArg for std::ffi::CString { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) @@ -178,28 +151,8 @@ impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr { } } -impl IntoDiagArg for ast::Visibility { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - let s = pprust::vis_to_string(&self); - let s = s.trim_end().to_string(); - DiagArgValue::Str(Cow::Owned(s)) - } -} - impl IntoDiagArg for Backtrace { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::from(self.to_string())) } } - -impl IntoDiagArg for ast::util::parser::ExprPrecedence { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Number(self as i32) - } -} - -impl IntoDiagArg for ast::FloatTy { - fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { - DiagArgValue::Str(Cow::Borrowed(self.name_str())) - } -} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b8325f7ba3987..e50c232df2d86 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -423,6 +423,10 @@ pub trait MacResult { None } + fn make_method_receiver_expr(self: Box) -> Option> { + self.make_expr() + } + /// Creates zero or more items. fn make_items(self: Box) -> Option; 1]>> { None diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b5f85536d9cac..2b914a2664fe5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -27,7 +27,7 @@ use rustc_hir::{ }; use rustc_parse::parser::Recovery; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::instrument; diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index d74b1787d83c8..a9493b8654805 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; -use rustc_ast::ast; use rustc_errors::codes::*; use rustc_hir::limit::Limit; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -230,7 +229,7 @@ pub(crate) struct WrongFragmentKind<'a> { #[primary_span] pub span: Span, pub kind: &'a str, - pub name: &'a ast::Path, + pub name: String, } #[derive(Diagnostic)] @@ -249,7 +248,7 @@ pub(crate) struct IncompleteParse<'a> { pub descr: String, #[label("caused by the macro expansion here")] pub label_span: Span, - pub macro_path: &'a ast::Path, + pub macro_path: String, pub kind_name: &'a str, #[note("macros cannot expand to match arms")] pub expands_to_match_arm: bool, diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index fe363e7d4a511..2bb6c43f3dd62 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -30,8 +30,8 @@ use rustc_parse::parser::{ RecoverColon, RecoverComma, Recovery, token_descr, }; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; -use rustc_session::parse::feature_err; use rustc_span::hygiene::SyntaxContext; use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym}; use smallvec::SmallVec; @@ -55,14 +55,11 @@ macro_rules! ast_fragments { $($Kind:ident($AstTy:ty) { $kind_name:expr; $(one - fn $mut_visit_ast:ident; fn $visit_ast:ident; - fn $ast_to_string:path; )? $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*); - fn $ast_to_string_elt:path; )? fn $make_ast:ident; })* @@ -71,7 +68,6 @@ macro_rules! ast_fragments { /// Can also serve as an input and intermediate result for macro expansion operations. pub enum AstFragment { OptExpr(Option>), - MethodReceiverExpr(Box), $($Kind($AstTy),)* } @@ -79,7 +75,6 @@ macro_rules! ast_fragments { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, - MethodReceiverExpr, $($Kind,)* } @@ -87,7 +82,6 @@ macro_rules! ast_fragments { pub fn name(self) -> &'static str { match self { AstFragmentKind::OptExpr => "expression", - AstFragmentKind::MethodReceiverExpr => "expression", $(AstFragmentKind::$Kind => $kind_name,)* } } @@ -96,8 +90,6 @@ macro_rules! ast_fragments { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), - AstFragmentKind::MethodReceiverExpr => - result.make_expr().map(AstFragment::MethodReceiverExpr), $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* } } @@ -120,21 +112,14 @@ macro_rules! ast_fragments { pub(crate) fn make_opt_expr(self) -> Option> { match self { AstFragment::OptExpr(expr) => expr, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), - } - } - - pub(crate) fn make_method_receiver_expr(self) -> Box { - match self { - AstFragment::MethodReceiverExpr(expr) => expr, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + _ => panic!("AstFragment::make_opt_expr called on the wrong kind of fragment"), } } $(pub fn $make_ast(self) -> $AstTy { match self { AstFragment::$Kind(ast) => ast, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + _ => panic!("AstFragment::{} called on the wrong kind of fragment", stringify!($make_ast)), } })* @@ -149,8 +134,7 @@ macro_rules! ast_fragments { *opt_expr = vis.filter_map_expr(expr) } } - AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), - $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* + $($(AstFragment::$Kind(ast) => vis.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)* } @@ -160,27 +144,11 @@ macro_rules! ast_fragments { match self { AstFragment::OptExpr(Some(expr)) => try_visit!(visitor.visit_expr(expr)), AstFragment::OptExpr(None) => {} - AstFragment::MethodReceiverExpr(expr) => try_visit!(visitor.visit_method_receiver_expr(expr)), $($(AstFragment::$Kind(ast) => try_visit!(visitor.$visit_ast(ast)),)?)* $($(AstFragment::$Kind(ast) => walk_list!(visitor, $visit_ast_elt, &ast[..], $($args)*),)?)* } V::Result::output() } - - pub(crate) fn to_string(&self) -> String { - match self { - AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr), - AstFragment::OptExpr(None) => unreachable!(), - AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr), - $($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)* - $($( - AstFragment::$Kind(ast) => { - // The closure unwraps a `P` if present, or does nothing otherwise. - elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast)) - } - )?)* - } - } } impl<'a, 'b> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a, 'b> { @@ -195,94 +163,97 @@ macro_rules! ast_fragments { ast_fragments! { Expr(Box) { "expression"; - one fn visit_expr; fn visit_expr; fn pprust::expr_to_string; + one fn visit_expr; fn make_expr; } + MethodReceiverExpr(Box) { + "expression"; + one fn visit_method_receiver_expr; + fn make_method_receiver_expr; + } Pat(Box) { "pattern"; - one fn visit_pat; fn visit_pat; fn pprust::pat_to_string; + one fn visit_pat; fn make_pat; } Ty(Box) { "type"; - one fn visit_ty; fn visit_ty; fn pprust::ty_to_string; + one fn visit_ty; fn make_ty; } Stmts(SmallVec<[ast::Stmt; 1]>) { "statement"; - many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string; + many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; } Items(SmallVec<[Box; 1]>) { "item"; - many fn flat_map_item; fn visit_item(); fn pprust::item_to_string; + many fn flat_map_item; fn visit_item(); fn make_items; } TraitItems(SmallVec<[Box; 1]>) { "trait item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); - fn pprust::assoc_item_to_string; fn make_trait_items; } ImplItems(SmallVec<[Box; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); - fn pprust::assoc_item_to_string; fn make_impl_items; } TraitImplItems(SmallVec<[Box; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); - fn pprust::assoc_item_to_string; fn make_trait_impl_items; } ForeignItems(SmallVec<[Box; 1]>) { "foreign item"; - many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string; + many fn flat_map_foreign_item; fn visit_foreign_item(); fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { "match arm"; - many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string; + many fn flat_map_arm; fn visit_arm(); fn make_arms; } ExprFields(SmallVec<[ast::ExprField; 1]>) { "field expression"; - many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string; + many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; } PatFields(SmallVec<[ast::PatField; 1]>) { "field pattern"; - many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string; + many fn flat_map_pat_field; fn visit_pat_field(); fn make_pat_fields; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; - many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string; + many fn flat_map_generic_param; fn visit_generic_param(); fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { "function parameter"; - many fn flat_map_param; fn visit_param(); fn unreachable_to_string; + many fn flat_map_param; fn visit_param(); fn make_params; } FieldDefs(SmallVec<[ast::FieldDef; 1]>) { "field"; - many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string; + many fn flat_map_field_def; fn visit_field_def(); fn make_field_defs; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string; + "variant"; + many fn flat_map_variant; fn visit_variant(); fn make_variants; } WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { "where predicate"; - many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string; + many fn flat_map_where_predicate; fn visit_where_predicate(); fn make_where_predicates; } Crate(ast::Crate) { "crate"; - one fn visit_crate; fn visit_crate; fn unreachable_to_string; + one fn visit_crate; fn make_crate; } } @@ -713,8 +684,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { mac: &ast::MacCall, span: Span, ) -> ErrorGuaranteed { - let guar = - self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); + let name = pprust::path_to_string(&mac.path); + let guar = self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name }); self.cx.macro_error_and_trace_macros_diag(); guar } @@ -1218,7 +1189,7 @@ pub(crate) fn ensure_complete_parse<'a>( span: def_site_span, descr, label_span: span, - macro_path, + macro_path: pprust::path_to_string(macro_path), kind_name, expands_to_match_arm, add_semicolon, diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index eed13a13fa911..cb22ad136645b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -23,7 +23,8 @@ use rustc_lint_defs::builtin::{ use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_session::parse::{ParseSess, feature_err}; +use rustc_session::errors::feature_err; +use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 92d19820848b4..443a17287d734 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_feature::Features; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edition::Edition; use rustc_span::{Ident, Span, kw, sym}; diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index 0d60141f274ec..d7bd5329da8b3 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -32,8 +32,34 @@ pub(crate) fn elems_to_string(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> Str s } -pub(crate) fn unreachable_to_string(_: &T) -> String { - unreachable!() +fn fragment_to_string(fragment: &AstFragment) -> String { + match fragment { + AstFragment::OptExpr(Some(expr)) + | AstFragment::MethodReceiverExpr(expr) + | AstFragment::Expr(expr) => pprust::expr_to_string(expr), + AstFragment::Pat(ast) => pprust::pat_to_string(ast), + AstFragment::Ty(ast) => pprust::ty_to_string(ast), + AstFragment::Stmts(ast) => elems_to_string(ast, pprust::stmt_to_string), + AstFragment::Items(ast) => elems_to_string(ast, |ast| pprust::item_to_string(ast)), + AstFragment::TraitItems(ast) + | AstFragment::ImplItems(ast) + | AstFragment::TraitImplItems(ast) => { + elems_to_string(ast, |ast| pprust::assoc_item_to_string(ast)) + } + AstFragment::ForeignItems(ast) => { + elems_to_string(ast, |ast| pprust::foreign_item_to_string(ast)) + } + AstFragment::OptExpr(None) + | AstFragment::Crate(_) + | AstFragment::Arms(_) + | AstFragment::ExprFields(_) + | AstFragment::PatFields(_) + | AstFragment::GenericParams(_) + | AstFragment::Params(_) + | AstFragment::FieldDefs(_) + | AstFragment::Variants(_) + | AstFragment::WherePredicates(_) => unreachable!(), + } } pub(crate) fn update_bang_macro_stats( @@ -98,7 +124,7 @@ pub(crate) fn update_attr_macro_stats( let input = format!( "{}\n{}", pprust::attribute_to_string(attr), - fragment_kind.expect_from_annotatables(iter::once(item)).to_string(), + fragment_to_string(&fragment_kind.expect_from_annotatables(iter::once(item))), ); update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment); } @@ -129,7 +155,7 @@ pub(crate) fn update_macro_stats( // Measure the size of the output by pretty-printing it and counting // the lines and bytes. let name = Symbol::intern(&pprust::path_to_string(path)); - let output = fragment.to_string(); + let output = fragment_to_string(fragment); let num_lines = output.trim_end().split('\n').count(); let num_bytes = output.len(); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e1f562ca3a59b..d77031564db5d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -420,6 +420,9 @@ declare_features! ( (unstable, bpf_target_feature, "1.54.0", Some(150247)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), + /// Allows defining c-variadic functions on targets where this feature has not yet + /// undergone sufficient testing for stabilization. + (unstable, c_variadic_experimental_arch, "CURRENT_RUSTC_VERSION", Some(155973)), /// Allows defining c-variadic naked functions with any extern ABI that is allowed /// on c-variadic foreign functions. (unstable, c_variadic_naked_functions, "1.93.0", Some(148767)), @@ -750,6 +753,8 @@ declare_features! ( (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), + /// Allows view types. + (unstable, view_types, "CURRENT_RUSTC_VERSION", Some(155938)), /// Target features on wasm. (unstable, wasm_target_feature, "1.30.0", Some(150260)), /// Allows use of attributes in `where` clauses. diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index 0d9fc669bda7f..fdc419c37dd34 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -18,7 +18,7 @@ pub struct DelayedLint { pub id: HirId, pub span: MultiSpan, pub callback: Box< - dyn for<'a> Fn(DiagCtxtHandle<'a>, Level, &dyn std::any::Any) -> Diag<'a, ()> + dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn std::any::Any) -> Diag<'a, ()> + DynSend + DynSync + 'static, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fcdbb11b297c1..3225e00b24b26 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -92,7 +92,7 @@ use rustc_middle::ty::{ Unnormalized, }; use rustc_middle::{bug, span_bug}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -312,7 +312,7 @@ fn default_body_is_unstable( }); let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span()); - rustc_session::parse::add_feature_diagnostics_for_issue( + rustc_session::errors::add_feature_diagnostics_for_issue( &mut err, &tcx.sess, feature, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 05d16d2ddb49c..d0277d2e24264 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{ Unnormalized, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt}; diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 07ad5db47b6d8..05a9f68131819 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -11,7 +11,7 @@ use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, elaborate}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{ErrorGuaranteed, sym}; use tracing::debug; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3a2f3948f0abc..d8cf13db265fd 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1272,7 +1272,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait() { - let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err( + let mut diag: rustc_errors::Diag<'_> = rustc_session::errors::feature_err( &self.tcx.sess, sym::anonymous_lifetime_in_impl_trait, lifetime_ref.ident.span, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 41b1ec91e0e75..3ac603fc715f3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -505,7 +505,7 @@ fn infer_placeholder_type<'tcx>( fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { if !tcx.features().inherent_associated_types() { - use rustc_session::parse::feature_err; + use rustc_session::errors::feature_err; use rustc_span::sym; feature_err( &tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 0aa478f99200b..5e11819805e15 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_param, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5096e5ef76f0d..75ea42a38ff4c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -43,8 +43,8 @@ use rustc_middle::ty::{ const_lit_matches_ty, fold_regions, }; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; -use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 0721bfcab519a..9cadaef8f886b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -89,7 +89,7 @@ use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{Const, Ty, TyCtxt}; use rustc_middle::{middle, ty}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 71c02dc32f6b5..664c3c457876c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -30,8 +30,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TypeVisitableExt, Unnormalized}; use rustc_middle::{bug, span_bug}; -use rustc_session::errors::ExprParenthesesNeeded; -use rustc_session::parse::feature_err; +use rustc_session::errors::{ExprParenthesesNeeded, feature_err}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::{Ident, Span, Spanned, Symbol, kw, sym}; @@ -3767,7 +3766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); if !self.tcx.features().offset_of_enum() { - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( &self.tcx.sess, sym::offset_of_enum, ident.span, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5a4cd6d24a8b6..d7f15222376c8 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -21,8 +21,8 @@ use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt, Unnormalized}; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym}; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 38d899853cd5b..cb41974af41b0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -39,8 +39,8 @@ use rustc_resolve::{Resolver, ResolverOutputs}; use rustc_session::Session; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; +use rustc_session::errors::feature_err; use rustc_session::output::{filename_for_input, invalid_output_for_target}; -use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, @@ -1016,23 +1016,38 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.output_filenames(Arc::new(outputs)); - let res = f(tcx); - // FIXME maybe run finish even when a fatal error occurred? or at least - // tcx.alloc_self_profile_query_strings()? + // There are two paths out of `f`. + // - Normal exit. + // - Panic, e.g. triggered by `abort_if_errors` or a fatal error. + // + // If a panic occurs, we still need to wind down the self-profiler to correctly record + // the query events that are still in flight. Otherwise, they will be invalid and will + // show up as "" in the profiling data. + let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(tcx))); + let res = match res { + Ok(res) => res, + Err(err) => { + tcx.alloc_self_profile_query_strings(); + + // Resume unwinding if a panic happened. + std::panic::resume_unwind(err); + } + }; + tcx.finish(); res }, ) } -struct DiagCallback<'a, 'tcx> { - callback: &'a Box< - dyn for<'b> Fn(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + DynSync, +struct DiagCallback<'tcx> { + callback: Box< + dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + DynSync, >, tcx: TyCtxt<'tcx>, } -impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for DiagCallback<'b, 'tcx> { +impl<'a, 'tcx> Diagnostic<'a, ()> for DiagCallback<'tcx> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { (self.callback)(dcx, level, self.tcx.sess) } @@ -1046,7 +1061,7 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) { lint.lint_id.lint, lint.id, lint.span.clone(), - DiagCallback { callback: &lint.callback, tcx }, + DiagCallback { callback: lint.callback, tcx }, ); } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 2b859b65c9f8f..8f68f6b8abf40 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -671,7 +671,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { continue; } - let (level, lint_id) = match Level::from_attr(attr) { + let (level, lint_id) = match Level::from_attr(attr.name(), || attr.id()) { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from // an attribute. @@ -966,7 +966,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let mut lint = Diag::new(dcx, level, msg!("unknown lint: `{$name}`")) .with_arg("name", lint_id.lint.name_lower()) .with_note(msg!("the `{$name}` lint is unstable")); - rustc_session::parse::add_feature_diagnostics_for_issue( + rustc_session::errors::add_feature_diagnostics_for_issue( &mut lint, sess, feature, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1e3ce972a3667..6d9f486f627f6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -306,7 +306,7 @@ impl<'a> Diagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { let mut diag = Diag::new(dcx, level, "`#[track_caller]` on async functions is a no-op") .with_span_label(self.label, "this function will not propagate the caller location"); - rustc_session::parse::add_feature_diagnostics( + rustc_session::errors::add_feature_diagnostics( &mut diag, self.session, sym::async_fn_track_caller, diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index c8201d5ea8ccc..2ca62f7fa8cdc 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_hir_id = { path = "../rustc_hir_id" } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 0f924d425f840..aa4b731a29bbc 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,8 +1,6 @@ use std::borrow::Cow; use std::fmt::Display; -use rustc_ast::AttrId; -use rustc_ast::attr::AttributeExt; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hasher::{ HashStable, HashStableContext, StableCompare, StableHasher, ToStableHashKey, @@ -12,7 +10,7 @@ use rustc_hir_id::{HirId, ItemLocalId}; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::def_id::DefPathHash; pub use rustc_span::edition::Edition; -use rustc_span::{Ident, Symbol, sym}; +use rustc_span::{AttrId, Ident, Symbol, sym}; use serde::{Deserialize, Serialize}; pub use self::Level::*; @@ -238,8 +236,11 @@ impl Level { } /// Converts an `Attribute` to a level. - pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option)> { - attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id()))) + pub fn from_attr( + attr_name: Option, + attr_id: impl Fn() -> AttrId, + ) -> Option<(Self, Option)> { + attr_name.and_then(|name| Self::from_symbol(name, || Some(attr_id()))) } /// Converts a `Symbol` to a level. diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index 03ea396a42c75..9affbf5f1583b 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -34,16 +34,19 @@ pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To let bindings = &vi.bindings(); vi.construct(|_, index| { let bi = &bindings[index]; - quote! { __tcx.lift(#bi)? } + quote! { __tcx.lift(#bi) } }) }); s.add_impl_generic(newtcx); - s.bound_impl(quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), quote! { - type Lifted = #lifted; + s.bound_impl( + quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), + quote! { + type Lifted = #lifted; - fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { - Some(match self { #body }) - } - }) + fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> #lifted { + match self { #body } + } + }, + ) } diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 0ae774ebee795..3d0971ed1ffd9 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -46,8 +46,8 @@ macro_rules! TrivialLiftImpls { $( impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty { type Lifted = Self; - fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Option { - Some(self) + fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Self { + self } } )+ diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index f9821c92df369..2c59517847370 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -11,9 +11,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stability}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; +use rustc_session::errors::feature_err_issue; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE}; use rustc_session::lint::{DeprecatedSinceKind, Level, Lint}; -use rustc_session::parse::feature_err_issue; use rustc_span::{Span, Symbol, sym}; use tracing::debug; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index de3ef6deca1fc..c3dd68fdd9187 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -493,7 +493,7 @@ impl<'tcx> Display for Const<'tcx> { // FIXME(valtrees): Correctly print mir constants. Const::Unevaluated(c, _ty) => { ty::tls::with(move |tcx| { - let c = tcx.lift(c).unwrap(); + let c = tcx.lift(c); // Matches `GlobalId` printing. let instance = with_no_trimmed_paths!(tcx.def_path_str_with_args(c.def, c.args)); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d160aada80a83..c59e6b6fa2151 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1165,7 +1165,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Adt(adt_did, variant, args, _user_ty, _) => { ty::tls::with(|tcx| { let variant_def = &tcx.adt_def(adt_did).variant(variant); - let args = tcx.lift(args).expect("could not lift for printing"); + let args = tcx.lift(args); let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { p.print_def_path(variant_def.def_id, args) })?; @@ -1187,7 +1187,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Closure(def_id, args) | AggregateKind::CoroutineClosure(def_id, args) => ty::tls::with(|tcx| { let name = if tcx.sess.opts.unstable_opts.span_free_formats { - let args = tcx.lift(args).unwrap(); + let args = tcx.lift(args); format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),) } else { let span = tcx.def_span(def_id); @@ -1911,8 +1911,6 @@ fn pretty_print_const_value_tcx<'tcx>( // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // to be able to destructure the tuple into `(0u8, *mut T)` (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { - let ct = tcx.lift(ct).unwrap(); - let ty = tcx.lift(ty).unwrap(); if let Some(contents) = tcx.try_destructure_mir_constant_for_user_output(ct, ty) { let fields: Vec<(ConstValue, Ty<'_>)> = contents.fields.to_vec(); match *ty.kind() { @@ -1937,7 +1935,6 @@ fn pretty_print_const_value_tcx<'tcx>( .variant .expect("destructed mir constant of adt without variant idx"); let variant_def = &def.variant(variant_idx); - let args = tcx.lift(args).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; p.pretty_print_value_path(variant_def.def_id, args)?; @@ -1974,7 +1971,6 @@ fn pretty_print_const_value_tcx<'tcx>( (ConstValue::Scalar(scalar), _) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - let ty = tcx.lift(ty).unwrap(); p.pretty_print_const_scalar(scalar, ty)?; fmt.write_str(&p.into_buffer())?; return Ok(()); @@ -2000,8 +1996,7 @@ pub(crate) fn pretty_print_const_value<'tcx>( fmt: &mut Formatter<'_>, ) -> fmt::Result { ty::tls::with(|tcx| { - let ct = tcx.lift(ct).unwrap(); - let ty = tcx.lift(ty).unwrap(); + let ty = tcx.lift(ty); pretty_print_const_value_tcx(tcx, ct, ty, fmt) }) } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 50242613b3e7f..8866860661c41 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -238,9 +238,8 @@ impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { impl<'tcx> fmt::Display for Value<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(move |tcx| { - let cv = tcx.lift(*self).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); - p.pretty_print_const_valtree(cv, /*print_ty*/ true)?; + p.pretty_print_const_valtree(tcx.lift(*self), /*print_ty*/ true)?; f.write_str(&p.into_buffer()) }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2e9708483a85b..b1927e190f033 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -958,7 +958,7 @@ impl<'tcx> TyCtxt<'tcx> { (start, end) } - pub fn lift>>(self, value: T) -> Option { + pub fn lift>>(self, value: T) -> T::Lifted { value.lift_to_interner(self) } @@ -1689,7 +1689,8 @@ macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for $ty { type Lifted = $lifted; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + #[track_caller] + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { // Assert that the set has the right type. // Given an argument that has an interned type, the return type has the type of // the corresponding interner set. This won't actually return anything, we're @@ -1709,12 +1710,10 @@ macro_rules! nop_lift { _type_eq(&interner, &tcx.interners.$set); } - tcx.interners - .$set - .contains_pointer_to(&InternedInSet(&*self.0.0)) - // SAFETY: `self` is interned and therefore valid - // for the entire lifetime of the `TyCtxt`. - .then(|| unsafe { mem::transmute(self) }) + assert!(tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0))); + // SAFETY: we just checked that `self` is interned and therefore is valid for the + // entire lifetime of the `TyCtxt`. + unsafe { mem::transmute(self) } } } }; @@ -1724,19 +1723,19 @@ macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { // Assert that the set has the right type. if false { let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; } if self.is_empty() { - return Some(List::empty()); + return List::empty(); } - tcx.interners - .$set - .contains_pointer_to(&InternedInSet(self)) - .then(|| unsafe { mem::transmute(self) }) + assert!(tcx.interners.$set.contains_pointer_to(&InternedInSet(self))); + // SAFETY: we just checked that `self` is interned and therefore is valid for the + // entire lifetime of the `TyCtxt`. + unsafe { mem::transmute(self) } } } }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index a4c30f1f88434..082e5de16cf98 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -223,10 +223,8 @@ impl<'tcx> TyCtxt<'tcx> { T: Copy + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { let mut type_limit = 50; - let regular = FmtPrinter::print_string(self, ns, |p| { - self.lift(t).expect("could not lift for printing").print(p) - }) - .expect("could not write to `String`"); + let regular = FmtPrinter::print_string(self, ns, |p| self.lift(t).print(p)) + .expect("could not write to `String`"); if regular.len() <= length_limit { return regular; } @@ -235,10 +233,7 @@ impl<'tcx> TyCtxt<'tcx> { // Look for the longest properly trimmed path that still fits in length_limit. short = with_forced_trimmed_paths!({ let mut p = FmtPrinter::new_with_limit(self, ns, Limit(type_limit)); - self.lift(t) - .expect("could not lift for printing") - .print(&mut p) - .expect("could not print type"); + self.lift(t).print(&mut p).expect("could not print type"); p.into_buffer() }); if short.len() <= length_limit || type_limit == 0 { @@ -273,10 +268,8 @@ impl<'tcx> TyCtxt<'tcx> { where T: Copy + Hash + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { - let regular = FmtPrinter::print_string(self, namespace, |p| { - self.lift(t).expect("could not lift for printing").print(p) - }) - .expect("could not write to `String`"); + let regular = FmtPrinter::print_string(self, namespace, |p| self.lift(t).print(p)) + .expect("could not write to `String`"); if !self.sess.opts.unstable_opts.write_long_types_to_disk || self.sess.opts.verbose { return regular; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index daeabf24d749f..c57c0851d8a49 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -320,11 +320,11 @@ impl<'tcx> GenericArg<'tcx> { impl<'a, 'tcx> Lift> for GenericArg<'a> { type Lifted = GenericArg<'tcx>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { match self.kind() { - GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()), - GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()), - GenericArgKind::Const(ct) => tcx.lift(ct).map(|ct| ct.into()), + GenericArgKind::Lifetime(lt) => tcx.lift(lt).into(), + GenericArgKind::Type(ty) => tcx.lift(ty).into(), + GenericArgKind::Const(ct) => tcx.lift(ct).into(), } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 408edf19dbf23..8166053f9bd5f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -381,8 +381,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); - let instance = tcx.lift(*self).expect("could not lift for printing"); - instance.print(&mut p)?; + tcx.lift(*self).print(&mut p)?; let s = p.into_buffer(); f.write_str(&s) }) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d2ae226c4d8dc..d5d1c3634c7d1 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -418,7 +418,7 @@ where fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); - tcx.lift(*t).expect("could not lift for printing").print(&mut p)?; + tcx.lift(*t).print(&mut p)?; fmt.write_str(&p.into_buffer())?; Ok(()) }) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f997e49868ba8..04d76e4304fe9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2082,10 +2082,9 @@ pub(crate) fn pretty_print_const<'tcx>( print_types: bool, ) -> fmt::Result { ty::tls::with(|tcx| { - let literal = tcx.lift(c).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - p.pretty_print_const(literal, print_types)?; + p.pretty_print_const(tcx.lift(c), print_types)?; fmt.write_str(&p.into_buffer())?; Ok(()) }) @@ -3098,7 +3097,6 @@ macro_rules! forward_display_to_print { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); tcx.lift(*self) - .expect("could not lift for printing") .print(&mut p)?; f.write_str(&p.into_buffer())?; Ok(()) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 29b784e837954..bc53fc18b41b6 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -271,20 +271,17 @@ TrivialTypeTraversalAndLiftImpls! { impl<'tcx, T: Lift>> Lift> for Option { type Lifted = Option; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { - Some(match self { - Some(x) => Some(tcx.lift(x)?), - None => None, - }) + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { + self.map(|x| tcx.lift(x)) } } impl<'a, 'tcx> Lift> for Term<'a> { type Lifted = ty::Term<'tcx>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { match self.kind() { - TermKind::Ty(ty) => tcx.lift(ty).map(Into::into), - TermKind::Const(c) => tcx.lift(c).map(Into::into), + TermKind::Ty(ty) => tcx.lift(ty).into(), + TermKind::Const(c) => tcx.lift(c).into(), } } } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 91610e768d012..6baf82f1335d0 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1298,7 +1298,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { break; } - if self.tcx.hir_attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { + if self + .tcx + .hir_attrs(id) + .iter() + .any(|attr| Level::from_attr(attr.name(), || attr.id()).is_some()) + { // This is a rare case. It's for a node path that doesn't reach the root due to an // intervening lint level attribute. This result doesn't get cached. return id; diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1829592d6d16e..4043b9bca61c5 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -4,8 +4,7 @@ use std::borrow::Cow; use std::path::PathBuf; use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, Token}; -use rustc_ast::util::parser::ExprPrecedence; -use rustc_ast::{Path, Visibility}; +use rustc_ast_pretty::pprust; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, @@ -657,7 +656,7 @@ pub(crate) struct ExpectedStructField { #[primary_span] #[label("expected one of `,`, `:`, or `{\"}\"}`")] pub span: Span, - pub token: Token, + pub token: Cow<'static, str>, #[label("while parsing this struct field")] pub ident_span: Span, } @@ -875,7 +874,7 @@ pub(crate) struct ComparisonInterpretedAsGeneric { #[primary_span] #[label("not interpreted as comparison")] pub comparison: Span, - pub r#type: Path, + pub r#type: String, #[label("interpreted as generic arguments")] pub args: Span, #[subdiagnostic] @@ -897,7 +896,7 @@ pub(crate) struct ShiftInterpretedAsGeneric { #[primary_span] #[label("not interpreted as shift")] pub shift: Span, - pub r#type: Path, + pub r#type: String, #[label("interpreted as generic arguments")] pub args: Span, #[subdiagnostic] @@ -919,7 +918,7 @@ pub(crate) struct FoundExprWouldBeStmt { #[primary_span] #[label("expected expression")] pub span: Span, - pub token: Token, + pub token: Cow<'static, str>, #[subdiagnostic] pub suggestion: ExprParenthesesNeeded, } @@ -1028,7 +1027,7 @@ pub(crate) struct ParenthesesWithStructFields { applicability = "maybe-incorrect" )] pub(crate) struct BracesForStructLiteral { - pub r#type: Path, + pub r#type: String, #[suggestion_part(code = " {{ ")] pub first: Span, #[suggestion_part(code = " }}")] @@ -1041,7 +1040,7 @@ pub(crate) struct BracesForStructLiteral { applicability = "maybe-incorrect" )] pub(crate) struct NoFieldsForFnCall { - pub r#type: Path, + pub r#type: String, #[suggestion_part(code = "")] pub fields: Vec, } @@ -1511,7 +1510,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedIdentifier { ); diag.span(self.span); if add_token { - diag.arg("token", self.token); + diag.arg("token", pprust::token_to_string(&self.token)); } if let Some(sugg) = self.suggest_raw { @@ -1577,7 +1576,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for ExpectedSemi { ); diag.span(self.span); if add_token { - diag.arg("token", self.token); + diag.arg("token", pprust::token_to_string(&self.token)); } if let Some(unexpected_token_label) = self.unexpected_token_label { @@ -2218,7 +2217,7 @@ pub(crate) struct VisibilityNotFollowedByItem { #[primary_span] #[label("the visibility")] pub span: Span, - pub vis: Visibility, + pub vis: String, } #[derive(Diagnostic)] @@ -2533,14 +2532,14 @@ pub(crate) enum UnexpectedTokenAfterStructName { #[primary_span] #[label("expected `where`, `{\"{\"}`, `(`, or `;` after struct name")] span: Span, - token: Token, + token: Cow<'static, str>, }, #[diag("expected `where`, `{\"{\"}`, `(`, or `;` after struct name, found keyword `{$token}`")] Keyword { #[primary_span] #[label("expected `where`, `{\"{\"}`, `(`, or `;` after struct name")] span: Span, - token: Token, + token: Cow<'static, str>, }, #[diag( "expected `where`, `{\"{\"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`" @@ -2549,7 +2548,7 @@ pub(crate) enum UnexpectedTokenAfterStructName { #[primary_span] #[label("expected `where`, `{\"{\"}`, `(`, or `;` after struct name")] span: Span, - token: Token, + token: Cow<'static, str>, }, #[diag( "expected `where`, `{\"{\"}`, `(`, or `;` after struct name, found doc comment `{$token}`" @@ -2558,7 +2557,7 @@ pub(crate) enum UnexpectedTokenAfterStructName { #[primary_span] #[label("expected `where`, `{\"{\"}`, `(`, or `;` after struct name")] span: Span, - token: Token, + token: Cow<'static, str>, }, #[diag("expected `where`, `{\"{\"}`, `(`, or `;` after struct name, found metavar")] MetaVar { @@ -2571,13 +2570,14 @@ pub(crate) enum UnexpectedTokenAfterStructName { #[primary_span] #[label("expected `where`, `{\"{\"}`, `(`, or `;` after struct name")] span: Span, - token: Token, + token: Cow<'static, str>, }, } impl UnexpectedTokenAfterStructName { - pub(crate) fn new(span: Span, token: Token) -> Self { - match TokenDescription::from_token(&token) { + pub(crate) fn new(span: Span, orig_token: Token) -> Self { + let token = pprust::token_to_string(&orig_token); + match TokenDescription::from_token(&orig_token) { Some(TokenDescription::ReservedIdentifier) => Self::ReservedIdentifier { span, token }, Some(TokenDescription::Keyword) => Self::Keyword { span, token }, Some(TokenDescription::ReservedKeyword) => Self::ReservedKeyword { span, token }, @@ -2630,13 +2630,13 @@ pub(crate) enum UnexpectedNonterminal { Ident { #[primary_span] span: Span, - token: Token, + token: Cow<'static, str>, }, #[diag("expected a lifetime, found `{$token}`")] Lifetime { #[primary_span] span: Span, - token: Token, + token: Cow<'static, str>, }, } @@ -3212,7 +3212,7 @@ pub(crate) struct UnexpectedVertVertInPattern { pub(crate) struct TrailingVertSuggestion { #[primary_span] pub span: Span, - pub token: Token, + pub token: Cow<'static, str>, } #[derive(Diagnostic)] @@ -3224,7 +3224,7 @@ pub(crate) struct TrailingVertNotAllowed { pub suggestion: TrailingVertSuggestion, #[label("while parsing this or-pattern starting here")] pub start: Option, - pub token: Token, + pub token: Cow<'static, str>, #[note("alternatives in or-patterns are separated with `|`, not `||`")] pub note_double_vert: bool, } @@ -3441,8 +3441,10 @@ pub(crate) struct UnexpectedExpressionInPattern { pub span: Span, /// Was a `RangePatternBound` expected? pub is_bound: bool, - /// The unexpected expr's precedence (used in match arm guard suggestions). - pub expr_precedence: ExprPrecedence, + /// The unexpected expr's precedence. Not used directly in the error message, but needed for + /// the stashing of this error to work correctly. We store a `u32` rather than an + /// `ExprPrecedence` to avoid having to impl `IntoDiagArg` for `ExprPrecedence`. + pub expr_precedence: u32, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d55548dd72180..35c271cb70204 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -18,6 +18,7 @@ use rustc_ast::{ FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind, }; +use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic}; use rustc_literal_escaper::unescape_char; @@ -352,7 +353,7 @@ impl<'a> Parser<'a> { fn error_found_expr_would_be_stmt(&self, lhs: &Expr) { self.dcx().emit_err(errors::FoundExprWouldBeStmt { span: self.token.span, - token: self.token, + token: pprust::token_to_string(&self.token), suggestion: ExprParenthesesNeeded::surrounding(lhs.span), }); } @@ -729,7 +730,7 @@ impl<'a> Parser<'a> { token::Lt => { self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric { comparison: self.token.span, - r#type: path, + r#type: pprust::path_to_string(&path), args: args_span, suggestion: errors::ComparisonInterpretedAsGenericSugg { left: expr.span.shrink_to_lo(), @@ -739,7 +740,7 @@ impl<'a> Parser<'a> { } token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric { shift: self.token.span, - r#type: path, + r#type: pprust::path_to_string(&path), args: args_span, suggestion: errors::ShiftInterpretedAsGenericSugg { left: expr.span.shrink_to_lo(), @@ -1304,16 +1305,17 @@ impl<'a> Parser<'a> { self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")") { err.cancel(); + let type_str = pprust::path_to_string(&path); self.dcx() .create_err(errors::ParenthesesWithStructFields { span, braces_for_struct: errors::BracesForStructLiteral { first: open_paren, second: close_paren, - r#type: path.clone(), + r#type: type_str.clone(), }, no_fields_for_fn: errors::NoFieldsForFnCall { - r#type: path, + r#type: type_str, fields: fields .into_iter() .map(|field| field.span.until(field.expr.span)) @@ -4038,7 +4040,7 @@ impl<'a> Parser<'a> { return Err(this.dcx().create_err(errors::ExpectedStructField { span: this.look_ahead(1, |t| t.span), ident_span: this.token.span, - token: this.look_ahead(1, |t| *t), + token: pprust::token_to_string(&this.look_ahead(1, |t| *t)), })); } let (ident, expr) = if is_shorthand { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 96bd59e2519e1..bd45bbb6a8582 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -192,9 +192,11 @@ impl<'a> Parser<'a> { // At this point, we have failed to parse an item. if !matches!(vis.kind, VisibilityKind::Inherited) { - let mut err = this - .dcx() - .create_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + let vis_str = pprust::vis_to_string(&vis).trim_end().to_string(); + let mut err = this.dcx().create_err(errors::VisibilityNotFollowedByItem { + span: vis.span, + vis: vis_str, + }); if let Some((ident, _)) = this.token.ident() && !ident.is_used_keyword() && let Some((similar_kw, is_incorrect_case)) = ident diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 37b76fc26a486..6ca7f89c76776 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -1,6 +1,7 @@ use rustc_ast::token::NtExprKind::*; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, NonterminalKind, Token}; +use rustc_ast_pretty::pprust; use rustc_errors::PResult; use rustc_span::{Ident, kw}; @@ -176,7 +177,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Ident { span: self.token.span, - token: self.token, + token: pprust::token_to_string(&self.token), })) } } @@ -198,7 +199,7 @@ impl<'a> Parser<'a> { } else { Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime { span: self.token.span, - token: self.token, + token: pprust::token_to_string(&self.token), })) } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index f36127ec8f0a8..4e6d76fefd9c2 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -367,14 +367,15 @@ impl<'a> Parser<'a> { match (is_end_ahead, &self.token.kind) { (true, token::Or | token::OrOr) => { // A `|` or possibly `||` token shouldn't be here. Ban it. + let token = pprust::token_to_string(&self.token); self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, start: lo, suggestion: TrailingVertSuggestion { span: self.prev_token.span.shrink_to_hi().with_hi(self.token.span.hi()), - token: self.token, + token: token.clone(), }, - token: self.token, + token, note_double_vert: self.token.kind == token::OrOr, }); self.bump(); @@ -502,7 +503,7 @@ impl<'a> Parser<'a> { .create_err(UnexpectedExpressionInPattern { span, is_bound, - expr_precedence: expr.precedence(), + expr_precedence: expr.precedence() as u32, }) .stash(span, StashKey::ExprInPat) .unwrap(), diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 072975f445bf4..b5151cf20ab02 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -19,7 +19,7 @@ use crate::errors::{ NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; -use crate::parser::{FnContext, FnParseMode}; +use crate::parser::{ExpTokenPair, FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -768,6 +768,25 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; + if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) { + // & [mut] . { } + // ^ + // we are here + let view_start_span = self.token.span; + self.bump(); + let fields = self + .parse_delim_comma_seq( + ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, + ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, + |p| p.parse_ident(), + )? + .0; + // FIXME(scrabsha): actually propagate field view in the AST. + let _ = fields; + let view_end_span = self.prev_token.span; + let span = view_start_span.to(view_end_span); + self.psess.gated_spans.gate(sym::view_types, span); + } Ok(match pinned { Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 831199a59a432..2817cf3020ff9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -36,12 +36,12 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::errors::feature_err; use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index dc41bb1f687fe..165ad737fccb8 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -49,9 +49,9 @@ impl RustcInternal for DefId { fn internal<'tcx>( &self, tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, + _tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.def_ids[*self]).unwrap() + tables.def_ids[*self] } } @@ -78,7 +78,7 @@ impl RustcInternal for GenericArgKind { GenericArgKind::Type(ty) => ty.internal(tables, tcx).into(), GenericArgKind::Const(cnst) => cnst.internal(tables, tcx).into(), }; - tcx.lift(arg).unwrap() + arg } } @@ -101,7 +101,7 @@ impl RustcInternal for Ty { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.types[*self]).unwrap() + tcx.lift(tables.types[*self]) } } @@ -112,7 +112,7 @@ impl RustcInternal for TyConst { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.ty_consts[self.id]).unwrap() + tcx.lift(tables.ty_consts[self.id]) } } @@ -316,11 +316,10 @@ impl RustcInternal for FnSig { .set_abi(self.abi.internal(tables, tcx)) .set_safety(self.safety.internal(tables, tcx)) .set_c_variadic(self.c_variadic); - tcx.lift(rustc_ty::FnSig { + rustc_ty::FnSig { inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)), fn_sig_kind, - }) - .unwrap() + } } } @@ -358,16 +357,13 @@ impl RustcInternal for MirConst { let constant = tables.mir_consts[self.id]; match constant { rustc_middle::mir::Const::Ty(ty, ct) => { - rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) + rustc_middle::mir::Const::Ty(tcx.lift(ty), tcx.lift(ct)) } rustc_middle::mir::Const::Unevaluated(uneval, ty) => { - rustc_middle::mir::Const::Unevaluated( - tcx.lift(uneval).unwrap(), - tcx.lift(ty).unwrap(), - ) + rustc_middle::mir::Const::Unevaluated(tcx.lift(uneval), tcx.lift(ty)) } rustc_middle::mir::Const::Val(const_val, ty) => { - rustc_middle::mir::Const::Val(tcx.lift(const_val).unwrap(), tcx.lift(ty).unwrap()) + rustc_middle::mir::Const::Val(tcx.lift(const_val), tcx.lift(ty)) } } } @@ -400,7 +396,7 @@ impl RustcInternal for Instance { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.instances[self.def]).unwrap() + tcx.lift(tables.instances[self.def]) } } @@ -553,9 +549,9 @@ impl RustcInternal for AllocId { fn internal<'tcx>( &self, tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, + _tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.alloc_ids[*self]).unwrap() + tables.alloc_ids[*self] } } @@ -691,7 +687,7 @@ impl RustcInternal for Layout { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.layouts[*self]).unwrap() + tcx.lift(tables.layouts[*self]) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index d8c4cee7abbe4..56fbd8108786a 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -58,7 +58,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - tables.layout_id(cx.lift(*self).unwrap()) + tables.layout_id(cx.lift(*self)) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 0d04053aab76b..2bc23e2837048 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -864,7 +864,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let id = tables.intern_mir_const(cx.lift(*self).unwrap()); + let id = tables.intern_mir_const(cx.lift(*self)); match *self { mir::Const::Ty(ty, c) => MirConst::new( crate::ty::ConstantKind::Ty(c.stable(tables, cx)), @@ -885,8 +885,8 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { MirConst::new(ConstantKind::ZeroSized, ty, id) } mir::Const::Val(val, ty) => { - let ty = cx.lift(ty).unwrap(); - let val = cx.lift(val).unwrap(); + let ty = cx.lift(ty); + let val = cx.lift(val); let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables, cx)); let ty = ty.stable(tables, cx); MirConst::new(kind, ty, id) diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 4c4a51f7444bb..80453d838b880 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -408,7 +408,7 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - tables.intern_ty(cx.lift(*self).unwrap()) + tables.intern_ty(cx.lift(*self)) } } @@ -526,7 +526,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let ct = cx.lift(*self).unwrap(); + let ct = cx.lift(*self); let kind = match ct.kind() { ty::ConstKind::Value(cv) => { let const_val = cx.valtree_to_const_val(cv); @@ -967,7 +967,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let def = tables.instance_def(cx.lift(*self).unwrap()); + let def = tables.instance_def(cx.lift(*self)); let kind = match self.def { ty::InstanceKind::Item(..) => crate::mir::mono::InstanceKind::Item, ty::InstanceKind::Intrinsic(..) => crate::mir::mono::InstanceKind::Intrinsic, diff --git a/compiler/rustc_public/src/unstable/internal_cx/mod.rs b/compiler/rustc_public/src/unstable/internal_cx/mod.rs index 161f2754bed87..f178ced7224c1 100644 --- a/compiler/rustc_public/src/unstable/internal_cx/mod.rs +++ b/compiler/rustc_public/src/unstable/internal_cx/mod.rs @@ -44,7 +44,7 @@ impl<'tcx> InternalCx<'tcx> for TyCtxt<'tcx> { self } - fn lift>>(self, value: T) -> Option { + fn lift>>(self, value: T) -> T::Lifted { TyCtxt::lift(self, value) } diff --git a/compiler/rustc_public/src/unstable/mod.rs b/compiler/rustc_public/src/unstable/mod.rs index ec979eef40cd1..8c20a54018553 100644 --- a/compiler/rustc_public/src/unstable/mod.rs +++ b/compiler/rustc_public/src/unstable/mod.rs @@ -26,7 +26,7 @@ mod internal_cx; pub trait InternalCx<'tcx>: Copy + Clone { fn tcx(self) -> TyCtxt<'tcx>; - fn lift>>(self, value: T) -> Option; + fn lift>>(self, value: T) -> T::Lifted; fn mk_args_from_iter(self, iter: I) -> T::Output where diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index bb504bd0017a0..260b9cd2198cf 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -53,7 +53,7 @@ impl<'tcx, B: Bridge> AllocRangeHelpers<'tcx> for CompilerCtxt<'tcx, B> { } impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> { - pub fn lift>>(&self, value: T) -> Option { + pub fn lift>>(&self, value: T) -> T::Lifted { self.tcx.lift(value) } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 723890a2f1ca2..b60bfc3be4ebc 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -605,12 +605,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span, label: None, refer_to_type_directly: None, + use_let: None, sugg: None, static_or_const, is_self, - item: inner_item.as_ref().map(|(span, kind)| { + item: inner_item.as_ref().map(|(label_span, _, kind)| { errs::GenericParamsFromOuterItemInnerItem { - span: *span, + span: *label_span, descr: kind.descr().to_string(), is_self, } @@ -618,10 +619,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let sm = self.tcx.sess.source_map(); + // Note: do not early return for missing def_id here, + // we still want to provide suggestions for `Res::SelfTyParam` and `Res::SelfTyAlias`. let def_id = match outer_res { Res::SelfTyParam { .. } => { err.label = Some(Label::SelfTyParam(span)); - return self.dcx().create_err(err); + None } Res::SelfTyAlias { alias_to: def_id, .. } => { err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword( @@ -630,15 +633,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ))); err.refer_to_type_directly = current_self_ty.map(|snippet| errs::UseTypeDirectly { span, snippet }); - return self.dcx().create_err(err); + None } Res::Def(DefKind::TyParam, def_id) => { err.label = Some(Label::TyParam(self.def_span(def_id))); - def_id + Some(def_id) } Res::Def(DefKind::ConstParam, def_id) => { err.label = Some(Label::ConstParam(self.def_span(def_id))); - def_id + Some(def_id) } _ => { bug!( @@ -649,8 +652,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - if let HasGenericParams::Yes(span) = has_generic_params - && !matches!(inner_item, Some((_, ItemKind::Delegation(..)))) + if let Some((_, item_span, ItemKind::Const(_))) = inner_item.as_ref() { + err.use_let = Some(errs::GenericParamsFromOuterItemUseLet { + span: sm.span_until_whitespace(*item_span), + }); + } + + if let Some(def_id) = def_id + && let HasGenericParams::Yes(span) = has_generic_params + && !matches!(inner_item, Some((_, _, ItemKind::Delegation(..)))) { let name = self.tcx.item_name(def_id); let (span, snippet) = if span.is_empty() { @@ -2152,6 +2162,111 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()` } + /// Returns the path segments (as symbols) of a module, including `kw::Crate` at the start. + /// For example, for `crate::foo::bar`, returns `[Crate, foo, bar]`. + /// Returns `None` for block modules that don't have a `DefId`. + fn module_path_names(&self, module: Module<'ra>) -> Option> { + let mut path = Vec::new(); + let mut def_id = module.opt_def_id()?; + while let Some(parent) = self.tcx.opt_parent(def_id) { + if let Some(name) = self.tcx.opt_item_name(def_id) { + path.push(name); + } + if parent.is_top_level_module() { + break; + } + def_id = parent; + } + path.reverse(); + path.insert(0, kw::Crate); + Some(path) + } + + /// Shortens a candidate import path to use `super::` (up to 1 level) or `self::` (same module) + /// relative to the current scope, if possible. Only applies to crate-local items and + /// only when the resulting path is actually shorter than the original. + fn shorten_candidate_path( + &self, + suggestion: &mut ImportSuggestion, + current_module: Module<'ra>, + ) { + const MAX_SUPER_PATH_ITEMS_IN_SUGGESTION: usize = 1; + + // Only shorten local items. + if suggestion.did.is_none_or(|did| !did.is_local()) { + return; + } + + // Build current module path: [Crate, foo, bar, ...]. + let Some(current_mod_path) = self.module_path_names(current_module) else { + return; + }; + + // Normalise candidate path: filter out `PathRoot` (`::`), and if the path + // doesn't start with `Crate`, prepend it (edition 2015 paths are relative + // to the crate root without an explicit `crate::` prefix). + let candidate_names = { + let filtered_segments: Vec<_> = suggestion + .path + .segments + .iter() + .filter(|segment| segment.ident.name != kw::PathRoot) + .collect(); + + let mut candidate_names: Vec = + filtered_segments.iter().map(|segment| segment.ident.name).collect(); + if candidate_names.first() != Some(&kw::Crate) { + candidate_names.insert(0, kw::Crate); + } + if candidate_names.len() < 2 { + return; + } + candidate_names + }; + + // The candidate's module path is everything except the last segment (the item name). + let candidate_mod_names = &candidate_names[..candidate_names.len() - 1]; + + // Find the longest common prefix between the current module and candidate module paths. + let common_prefix_length = current_mod_path + .iter() + .zip(candidate_mod_names.iter()) + .take_while(|(current, candidate)| current == candidate) + .count(); + + // Non-crate-local item; keep the full absolute path. + if common_prefix_length == 0 { + return; + } + + let super_count = current_mod_path.len() - common_prefix_length; + + // At the crate root, `use` paths resolve from the crate root anyway, so we can + // drop the `crate::` prefix entirely instead of replacing it with `self::`. + let at_crate_root = current_mod_path.len() == 1; + + let mut new_segments = if super_count == 0 && at_crate_root { + ThinVec::new() + } else { + let prefix_keyword = match super_count { + 0 => kw::SelfLower, + 1..=MAX_SUPER_PATH_ITEMS_IN_SUGGESTION => kw::Super, + _ => return, // Too many `super` levels; keep the full absolute path. + }; + thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(prefix_keyword),)] + }; + for &name in &candidate_names[common_prefix_length..] { + new_segments.push(ast::PathSegment::from_ident(Ident::with_dummy_span(name))); + } + + // Only apply if the result is strictly shorter than the original path. + if new_segments.len() >= suggestion.path.segments.len() { + return; + } + + suggestion.path = Path { span: suggestion.path.span, segments: new_segments, tokens: None }; + } + fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { let PrivacyError { ident, @@ -2180,12 +2295,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { - let import_suggestions = self.lookup_import_candidates( + let mut import_suggestions = self.lookup_import_candidates( outer_ident, this_res.ns().unwrap_or(Namespace::TypeNS), &parent_scope, &|res: Res| res == this_res, ); + // Shorten candidate paths using `super::` or `self::` when possible. + for suggestion in &mut import_suggestions { + self.shorten_candidate_path(suggestion, parent_scope.module); + } let point_to_def = !show_candidates( self.tcx, &mut err, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 9f26fc076e57f..342484a8c0d51 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -32,6 +32,8 @@ pub(crate) struct GenericParamsFromOuterItem { #[subdiagnostic] pub(crate) refer_to_type_directly: Option, #[subdiagnostic] + pub(crate) use_let: Option, + #[subdiagnostic] pub(crate) sugg: Option, #[subdiagnostic] pub(crate) static_or_const: Option, @@ -86,6 +88,19 @@ pub(crate) struct GenericParamsFromOuterItemSugg { pub(crate) span: Span, pub(crate) snippet: String, } + +#[derive(Subdiagnostic)] +#[suggestion( + "try using a local `let` binding instead", + code = "let", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct GenericParamsFromOuterItemUseLet { + #[primary_span] + pub(crate) span: Span, +} + #[derive(Subdiagnostic)] #[suggestion( "refer to the type directly here instead", diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5fae50041a02d..658e36083b0ad 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -6,8 +6,8 @@ use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Span, kw, sym}; @@ -1589,12 +1589,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; @@ -1683,12 +1683,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2695655278fb4..360c14afa8ba6 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -18,11 +18,11 @@ use rustc_hir::def_id::{DefId, LocalDefIdMap}; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Ident, Span, Symbol, kw, sym}; @@ -1292,6 +1292,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; } + } else { + // The final item is not a module (e.g., a struct, function, or macro). + // Resolve it directly in the parent module to get its Res, so + // `report_privacy_error()` can search for public re-export paths. + for ns in [TypeNS, ValueNS, MacroNS] { + if let Ok(binding) = self.cm().resolve_ident_in_module( + module, + ident, + ns, + &import.parent_scope, + None, + ignore_decl, + None, + ) { + let res = binding.res(); + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + } + break; + } + } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6eb5fe17bc169..014a472c2c1bb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -32,8 +32,8 @@ use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; +use rustc_session::errors::feature_err; use rustc_session::lint; -use rustc_session::parse::feature_err; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Spanned, Symbol, kw, respan, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4d86da95e3fa8..c733299154ab7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -248,7 +248,8 @@ enum ResolutionError<'ra> { outer_res: Res, has_generic_params: HasGenericParams, def_kind: DefKind, - inner_item: Option<(Span, ast::ItemKind)>, + /// 1. label span, 2. item span, 3. item kind + inner_item: Option<(Span, Span, ast::ItemKind)>, current_self_ty: Option, }, /// Error E0403: the name is already used for a type or const parameter in this generic diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dc20d4fcf36b7..998cf27a85de1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -23,11 +23,11 @@ use rustc_hir::{Attribute, StabilityLevel}; use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS, }; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 54f88aa22bdc4..bc4c5e98282a5 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -5,14 +5,179 @@ use rustc_ast::util::literal::LitError; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, + MultiSpan, StashKey, }; +use rustc_feature::{GateIssue, find_feature_issue}; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple}; +use crate::Session; +use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; use crate::parse::ParseSess; +/// Construct a diagnostic for a language feature error due to the given `span`. +/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. +#[track_caller] +pub fn feature_err( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + feature_err_issue(sess, feature, span, GateIssue::Language, explain) +} + +/// Construct a diagnostic for a feature gate error. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. +#[track_caller] +pub fn feature_err_issue( + sess: &Session, + feature: Symbol, + span: impl Into, + issue: GateIssue, + explain: impl Into, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() + && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) + { + err.cancel() + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); + err +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +#[track_caller] +pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) { + feature_warn_issue(sess, feature, span, GateIssue::Language, explain); +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. +#[track_caller] +pub fn feature_warn_issue( + sess: &Session, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &'static str, +) { + let mut err = sess.dcx().struct_span_warn(span, explain); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); + + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level + let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; + let future_incompatible = lint.future_incompatible.as_ref().unwrap(); + err.is_lint(lint.name_lower(), /* has_future_breakage */ false); + err.warn(lint.desc); + err.note(format!("for more information, see {}", future_incompatible.reason.reference())); + + // A later feature_err call can steal and cancel this warning. + err.stash(span, StashKey::EarlySyntaxWarning); +} + +/// Adds the diagnostics for a feature to an existing error. +/// Must be a language feature! +pub fn add_feature_diagnostics( + err: &mut Diag<'_, G>, + sess: &Session, + feature: Symbol, +) { + add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); +} + +/// Adds the diagnostics for a feature to an existing error. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer +/// `add_feature_diagnostics`. +pub fn add_feature_diagnostics_for_issue( + err: &mut Diag<'_, G>, + sess: &Session, + feature: Symbol, + issue: GateIssue, + feature_from_cli: bool, + inject_span: Option, +) { + if let Some(n) = find_feature_issue(feature, issue) { + err.subdiagnostic(FeatureDiagnosticForIssue { n }); + } + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + if feature_from_cli { + err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); + } else if let Some(span) = inject_span { + err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); + } else { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + } + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } +} + +/// This is only used by unstable_feature_bound as it does not have issue number information for now. +/// This is basically the same as `feature_err_issue` +/// but without the feature issue note. If we can do a lookup for issue number from feature name, +/// then we should directly use `feature_err_issue` for ambiguity error of +/// `#[unstable_feature_bound]`. +#[track_caller] +pub fn feature_err_unstable_feature_bound( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { + err.cancel() + } + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } + err +} + #[derive(Diagnostic)] pub(crate) enum AppleDeploymentTarget { #[diag("failed to parse deployment target specified in {$env_var}: {$error}")] diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index c09e3eed37125..54058e9f5f046 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -1,7 +1,6 @@ //! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! It also serves as an input to the parser itself. -use std::str; use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; @@ -11,21 +10,15 @@ use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{EmitterWithNote, stderr_destination}; use rustc_errors::{ - BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, - DiagMessage, EmissionGuarantee, Level, MultiSpan, StashKey, + BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, Level, + MultiSpan, }; -use rustc_feature::{GateIssue, find_feature_issue}; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use crate::Session; -use crate::errors::{ - CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, - FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler, -}; -use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; use crate::lint::{Lint, LintId}; /// Collected spans during parsing for places where a certain feature was @@ -78,169 +71,6 @@ impl SymbolGallery { } } -// FIXME: this function now accepts `Session` instead of `ParseSess` and should be relocated -/// Construct a diagnostic for a language feature error due to the given `span`. -/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. -#[track_caller] -pub fn feature_err( - sess: &Session, - feature: Symbol, - span: impl Into, - explain: impl Into, -) -> Diag<'_> { - feature_err_issue(sess, feature, span, GateIssue::Language, explain) -} - -/// Construct a diagnostic for a feature gate error. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. -#[track_caller] -pub fn feature_err_issue( - sess: &Session, - feature: Symbol, - span: impl Into, - issue: GateIssue, - explain: impl Into, -) -> Diag<'_> { - let span = span.into(); - - // Cancel an earlier warning for this same error, if it exists. - if let Some(span) = span.primary_span() - && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) - { - err.cancel() - } - - let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); - err -} - -/// Construct a future incompatibility diagnostic for a feature gate. -/// -/// This diagnostic is only a warning and *does not cause compilation to fail*. -#[track_caller] -pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) { - feature_warn_issue(sess, feature, span, GateIssue::Language, explain); -} - -/// Construct a future incompatibility diagnostic for a feature gate. -/// -/// This diagnostic is only a warning and *does not cause compilation to fail*. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. -#[track_caller] -pub fn feature_warn_issue( - sess: &Session, - feature: Symbol, - span: Span, - issue: GateIssue, - explain: &'static str, -) { - let mut err = sess.dcx().struct_span_warn(span, explain); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); - - // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level - let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; - let future_incompatible = lint.future_incompatible.as_ref().unwrap(); - err.is_lint(lint.name_lower(), /* has_future_breakage */ false); - err.warn(lint.desc); - err.note(format!("for more information, see {}", future_incompatible.reason.reference())); - - // A later feature_err call can steal and cancel this warning. - err.stash(span, StashKey::EarlySyntaxWarning); -} - -/// Adds the diagnostics for a feature to an existing error. -/// Must be a language feature! -pub fn add_feature_diagnostics( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, -) { - add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); -} - -/// Adds the diagnostics for a feature to an existing error. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer -/// `add_feature_diagnostics`. -pub fn add_feature_diagnostics_for_issue( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, - issue: GateIssue, - feature_from_cli: bool, - inject_span: Option, -) { - if let Some(n) = find_feature_issue(feature, issue) { - err.subdiagnostic(FeatureDiagnosticForIssue { n }); - } - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - if feature_from_cli { - err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); - } else if let Some(span) = inject_span { - err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); - } else { - err.subdiagnostic(FeatureDiagnosticHelp { feature }); - } - if feature == sym::rustc_attrs { - // We're unlikely to stabilize something out of `rustc_attrs` - // without at least renaming it, so pointing out how old - // the compiler is will do little good. - } else if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); - } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(suggestion); - } - } -} - -/// This is only used by unstable_feature_bound as it does not have issue number information for now. -/// This is basically the same as `feature_err_issue` -/// but without the feature issue note. If we can do a lookup for issue number from feature name, -/// then we should directly use `feature_err_issue` for ambiguity error of -/// `#[unstable_feature_bound]`. -#[track_caller] -pub fn feature_err_unstable_feature_bound( - sess: &Session, - feature: Symbol, - span: impl Into, - explain: impl Into, -) -> Diag<'_> { - let span = span.into(); - - // Cancel an earlier warning for this same error, if it exists. - if let Some(span) = span.primary_span() { - if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { - err.cancel() - } - } - - let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - err.subdiagnostic(FeatureDiagnosticHelp { feature }); - - if feature == sym::rustc_attrs { - // We're unlikely to stabilize something out of `rustc_attrs` - // without at least renaming it, so pointing out how old - // the compiler is will do little good. - } else if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); - } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(suggestion); - } - } - err -} - /// Info about a parsing session. pub struct ParseSess { dcx: DiagCtxt, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 6c04a39063e34..5491e89f57f79 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -45,7 +45,7 @@ use crate::config::{ }; use crate::filesearch::FileSearch; use crate::lint::LintId; -use crate::parse::{ParseSess, add_feature_diagnostics}; +use crate::parse::ParseSess; use crate::search_paths::SearchPath; use crate::{errors, filesearch, lint}; @@ -282,7 +282,7 @@ impl Session { if err.code.is_none() { err.code(E0658); } - add_feature_diagnostics(&mut err, self, feature); + errors::add_feature_diagnostics(&mut err, self, feature); err } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index caeb923c18f78..702c3c54101c3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -548,6 +548,7 @@ symbols! { c_str_literals, c_unwind, c_variadic, + c_variadic_experimental_arch, c_variadic_naked_functions, c_void, call, @@ -2232,6 +2233,7 @@ symbols! { verbatim, version, vfp2, + view_types, vis, visible_private_types, volatile, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 209cece71f873..b910779537f38 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -47,7 +47,8 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{ - Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError, + Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, + TargetDataLayoutError, }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; @@ -2208,10 +2209,13 @@ impl Target { Ok(dl) } - pub fn supports_c_variadic_definitions(&self) -> bool { + pub fn supports_c_variadic_definitions(&self) -> CVariadicStatus { use Arch::*; match self.arch { + // These targets just inherently do not support c-variadic definitions. + Bpf | SpirV => CVariadicStatus::NotSupported, + // The c-variadic ABI for this target may change in the future, per this comment in // clang: // @@ -2219,19 +2223,40 @@ impl Target { // > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, // > `unsigned long long` and `double` to have 4-byte alignment. This // > behavior may be changed when RV32E/ILP32E is ratified. - RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false, - - // These targets just do not support c-variadic definitions. - Bpf | SpirV => false, + RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } // We don't know how c-variadics work for this target. Using the default LLVM - // fallback implementation may work, but just to be safe we disallow this. - Other(_) => false, + // fallback implementation probably works, but we can't guarantee it. + Other(_) => CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch }, - AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 - | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 - | X86_64 | Xtensa => true, + // These targets require more testing before we commit to c-variadic definitions + // being stable. + // + // To stabilize c-variadic functions for one of these targets, the following + // requirements must be met: + // + // - Check that `core::ffi::VaArgSafe` is (un)implemented for all the correct types. + // - Add an assembly test to `tests/assembly-llvm/c-variadic` that tests the assembly + // for all implementers of `VaArgSafe`. The generated assembly should either match + // `clang`, or we should understand and document why it deviates. + // - Ensure that `va_arg` is implemented in rustc. For stable targets we don't rely on + // the LLVM implementation, it has historically caused miscompilations. + // - The `tests/ui/c-variadic/roundtrip.rs` test must pass for the target. It may + // need slight modifications for embedded targets, that's fine. + // - Check that calling c-variadic functions defined in Rust can be called from C. + // For most targets `tests/run-make/c-link-to-rust-va-list-fn` can be used here. + // For no_std targets a manual setup may be needed. + Sparc | Avr | M68k | Msp430 => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } + + AArch64 | AmdGpu | Arm | Arm64EC | CSky | Hexagon | LoongArch32 | LoongArch64 + | Mips | Mips32r6 | Mips64 | Mips64r6 | Nvptx64 | PowerPC | PowerPC64 | RiscV32 + | RiscV64 | S390x | Sparc64 | Wasm32 | Wasm64 | X86 | X86_64 | Xtensa => { + CVariadicStatus::Stable + } } } } diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index c11edf7c618c2..b936a2ba2570d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs index f9a7d307c74a3..74a8a88dff674 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index 76c9ad65700c2..f362e694db4d2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 1a308ee334d3b..108262d507ef7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -13,7 +13,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::PrintPolyTraitPredicateExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _, Unnormalized}; -use rustc_session::parse::feature_err_unstable_feature_bound; +use rustc_session::errors::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 66a2fcaa562d1..57b14e93e277c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Span, sym}; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 79dff2ffbbce9..b45832744f82f 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -45,11 +45,11 @@ where { type Lifted = Binder; - fn lift_to_interner(self, cx: U) -> Option { - Some(Binder { - value: self.value.lift_to_interner(cx)?, - bound_vars: self.bound_vars.lift_to_interner(cx)?, - }) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + Binder { + value: self.value.lift_to_interner(cx), + bound_vars: self.bound_vars.lift_to_interner(cx), + } } } @@ -991,12 +991,12 @@ where { type Lifted = Placeholder; - fn lift_to_interner(self, cx: U) -> Option { - Some(Placeholder { + fn lift_to_interner(self, cx: U) -> Self::Lifted { + Placeholder { universe: self.universe, - bound: self.bound.lift_to_interner(cx)?, + bound: self.bound.lift_to_interner(cx), _tcx: PhantomData, - }) + } } } @@ -1186,8 +1186,8 @@ where { type Lifted = BoundTy; - fn lift_to_interner(self, cx: U) -> Option { - Some(BoundTy { var: self.var, kind: self.kind.lift_to_interner(cx)? }) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + BoundTy { var: self.var, kind: self.kind.lift_to_interner(cx) } } } diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index e5a099d1f5042..739d3a8512329 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -9,13 +9,13 @@ /// It would be more efficient if `TypedArena` provided a way to /// determine whether the address is in the allocated range. /// -/// `None` is returned if the value or one of the components is not part +/// Panics if the value or one of the components is not part /// of the provided context. -/// For `Ty`, `None` can be returned if either the type interner doesn't +/// For `Ty`, this can happen if either the type interner doesn't /// contain the `TyKind` key or if the address of the interned /// pointer differs. The latter case is possible if a primitive type, /// e.g., `()` or `u8`, was interned in a different context. pub trait Lift: std::fmt::Debug { type Lifted: std::fmt::Debug; - fn lift_to_interner(self, cx: I) -> Option; + fn lift_to_interner(self, cx: I) -> Self::Lifted; } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index fa03cec596549..b419a871f37d2 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -35,8 +35,8 @@ where { type Lifted = OutlivesPredicate; - fn lift_to_interner(self, cx: U) -> Option { - Some(OutlivesPredicate(self.0.lift_to_interner(cx)?, self.1.lift_to_interner(cx)?)) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + OutlivesPredicate(self.0.lift_to_interner(cx), self.1.lift_to_interner(cx)) } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index dd893a9288703..c5078115870c4 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -782,8 +782,8 @@ pub struct FnSigKind { impl crate::lift::Lift for FnSigKind { type Lifted = FnSigKind; - fn lift_to_interner(self, _cx: J) -> Option { - Some(FnSigKind { flags: self.flags, _marker: PhantomData }) + fn lift_to_interner(self, _cx: J) -> Self::Lifted { + FnSigKind { flags: self.flags, _marker: PhantomData } } } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 8df10b6a9eccd..7ea8bd384e3cf 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -168,7 +168,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift }); let bind = &bindings[index]; quote! { - #bind.lift_to_interner(interner)? + #bind.lift_to_interner(interner) } }) }); @@ -189,8 +189,8 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { fn lift_to_interner( self, interner: J, - ) -> Option { - Some(match self { #body_fold }) + ) -> Self::Lifted { + match self { #body_fold } } }, ) diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index 0a8b43622faef..a27f9e2deec94 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -251,6 +251,9 @@ impl VaList<'_> { #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] impl<'f> const Clone for VaList<'f> { + /// Clone the [`VaList`], producing a second independent cursor into the variable argument list. + /// + /// Corresponds to `va_copy` in C. #[inline] // Avoid codegen when not used to help backends that don't support VaList. fn clone(&self) -> Self { // We only implement Clone and not Copy because some future target might not be able to @@ -263,8 +266,14 @@ impl<'f> const Clone for VaList<'f> { #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] impl<'f> const Drop for VaList<'f> { + /// Drop the [`VaList`]. + /// + /// Corresponds to `va_end` in C. #[inline] // Avoid codegen when not used to help backends that don't support VaList. fn drop(&mut self) { + // Call the rust `va_end` intrinsic, which is a no-op and does not map to LLVM `va_end`. + // The rust intrinsic exists as a hook for Miri to check for UB. + // // SAFETY: this variable argument list is being dropped, so won't be read from again. unsafe { va_end(self) } } @@ -324,7 +333,7 @@ mod sealed { // types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used // to accept unsupported types in the meantime. #[lang = "va_arg_safe"] -pub unsafe trait VaArgSafe: sealed::Sealed {} +pub unsafe trait VaArgSafe: Copy + sealed::Sealed {} crate::cfg_select! { any(target_arch = "avr", target_arch = "msp430") => { @@ -381,6 +390,12 @@ const _: () = { va_arg_safe_check::(); va_arg_safe_check::(); + + va_arg_safe_check::<*const crate::ffi::c_void>(); + va_arg_safe_check::<*mut crate::ffi::c_void>(); + + va_arg_safe_check::<*const crate::ffi::c_char>(); + va_arg_safe_check::<*mut crate::ffi::c_char>(); }; impl<'f> VaList<'f> { diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index a9b4d182bd400..4038f112d59fd 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -15,7 +15,7 @@ struct Cli { /// Modify files that do not comply overwrite: bool, /// Applies to lines that are to be split - #[arg(long, default_value_t = 80)] + #[arg(long, default_value_t = 100)] line_length_limit: usize, } diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 1175e3372ab63..ea416dc27b52d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -cf1817bc6ecd2d14ca492247c804bad31948dd56 +f53b654a8882fd5fc036c4ca7a4ff41ce32497a6 diff --git a/src/doc/rustc-dev-guide/src/asm.md b/src/doc/rustc-dev-guide/src/asm.md index b5857d5465e15..9a87918538def 100644 --- a/src/doc/rustc-dev-guide/src/asm.md +++ b/src/doc/rustc-dev-guide/src/asm.md @@ -3,11 +3,13 @@ ## Overview Inline assembly in rustc mostly revolves around taking an `asm!` macro invocation and plumbing it -through all of the compiler layers down to LLVM codegen. Throughout the various stages, an -`InlineAsm` generally consists of 3 components: +through all of the compiler layers down to LLVM codegen. +Throughout the various stages, +an `InlineAsm` generally consists of 3 components: -- The template string, which is stored as an array of `InlineAsmTemplatePiece`. Each piece -represents either a literal or a placeholder for an operand (just like format strings). +- The template string, which is stored as an array of `InlineAsmTemplatePiece`. + Each piece represents either a literal or a placeholder for an operand + (just like format strings). ```rust pub enum InlineAsmTemplatePiece { @@ -16,23 +18,29 @@ represents either a literal or a placeholder for an operand (just like format st } ``` -- The list of operands to the `asm!` (`in`, `[late]out`, `in[late]out`, `sym`, `const`). These are -represented differently at each stage of lowering, but follow a common pattern: - - `in`, `out` and `inout` all have an associated register class (`reg`) or explicit register -(`"eax"`). - - `inout` has 2 forms: one with a single expression that is both read from and written to, and -one with two separate expressions for the input and output parts. +- The list of operands to the `asm!` (`in`, `[late]out`, `in[late]out`, `sym`, `const`). + These are represented differently at each stage of lowering, + but follow a common pattern: + - `in`, `out`, and `inout` all have an associated register class (`reg`) + or explicit register (`"eax"`). + - `inout` has 2 forms: + one with a single expression that is both read from and written to, + and one with two separate expressions for the input and output parts. - `out` and `inout` have a `late` flag (`lateout` / `inlateout`) to indicate that the register -allocator is allowed to reuse an input register for this output. - - `out` and the split variant of `inout` allow `_` to be specified for an output, which means -that the output is discarded. This is used to allocate scratch registers for assembly code. - - `const` refers to an anonymous constants and generally works like an inline const. - - `sym` is a bit special since it only accepts a path expression, which must point to a `static` -or a `fn`. - -- The options set at the end of the `asm!` macro. The only ones that are of particular interest to -rustc are `NORETURN` which makes `asm!` return `!` instead of `()`, and `RAW` which disables format -string parsing. The remaining options are mostly passed through to LLVM with little processing. + allocator is allowed to reuse an input register for this output. + - `out` and the split variant of `inout` allow `_` to be specified for an output, + which means that the output is discarded. + This is used to allocate scratch registers for assembly code. + - `const` refers to an anonymous constants, + and generally works like an inline const. + - `sym` is a bit special since it only accepts a path expression, + which must point to a `static` or a `fn`. + +- The options set at the end of the `asm!` macro. + The only ones that are of particular interest to + rustc are `NORETURN` which makes `asm!` return `!` instead of `()`, + and `RAW` which disables format string parsing. + The remaining options are mostly passed through to LLVM with little processing. ```rust bitflags::bitflags! { @@ -54,9 +62,10 @@ string parsing. The remaining options are mostly passed through to LLVM with lit `InlineAsm` is represented as an expression in the AST with the [`ast::InlineAsm` type][inline_asm_ast]. -The `asm!` macro is implemented in `rustc_builtin_macros` and outputs an `InlineAsm` AST node. The -template string is parsed using `fmt_macros`, positional and named operands are resolved to -explicit operand indices. Since target information is not available to macro invocations, +The `asm!` macro is implemented in `rustc_builtin_macros` and outputs an `InlineAsm` AST node. +The template string is parsed using `fmt_macros`, +positional and named operands are resolved to explicit operand indices. +Since target information is not available to macro invocations, validation of the registers and register classes is deferred to AST lowering. [inline_asm_ast]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/struct.InlineAsm.html @@ -66,18 +75,22 @@ validation of the registers and register classes is deferred to AST lowering. `InlineAsm` is represented as an expression in the HIR with the [`hir::InlineAsm` type][inline_asm_hir]. AST lowering is where `InlineAsmRegOrRegClass` is converted from `Symbol`s to an actual register or -register class. If any modifiers are specified for a template string placeholder, these are -validated against the set allowed for that operand type. Finally, explicit registers for inputs and +register class. +If any modifiers are specified for a template string placeholder, these are +validated against the set allowed for that operand type. +Finally, explicit registers for inputs and outputs are checked for conflicts (same register used for different operands). [inline_asm_hir]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.InlineAsm.html ## Type checking -Each register class has a whitelist of types that it may be used with. After the types of all -operands have been determined, the `intrinsicck` pass will check that these types are in the -whitelist. It also checks that split `inout` operands have compatible types and that `const` -operands are integers or floats. Suggestions are emitted where needed if a template modifier should +Each register class has an allowlist of types that it may be used with. +After the types of all operands have been determined, +the `intrinsicck` pass will check that these types are in the allowlist. +It also checks that split `inout` operands have compatible types and that `const` +operands are integers or floats. +Suggestions are emitted where needed if a template modifier should be used for an operand based on the type that was passed into it. ## THIR @@ -85,8 +98,8 @@ be used for an operand based on the type that was passed into it. `InlineAsm` is represented as an expression in the THIR with the [`InlineAsmExpr` type][inline_asm_thir]. The only significant change compared to HIR is that `Sym` has been lowered to either a `SymFn` -whose `expr` is a `Literal` ZST of the `fn`, or a `SymStatic` which points to the `DefId` of a -`static`. +whose `expr` is a `Literal` ZST of the `fn`, +or a `SymStatic` which points to the `DefId` of a `static`. [inline_asm_thir]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.InlineAsmExpr.html @@ -104,50 +117,59 @@ multiple output places where a `Call` only has a single return place output. ## Codegen -Operands are lowered one more time before being passed to LLVM codegen, this is represented by the [`InlineAsmOperandRef` type][inline_asm_codegen] from `rustc_codegen_ssa`. +Operands are lowered one more time before being passed to LLVM codegen. +This is represented by the [`InlineAsmOperandRef` type][inline_asm_codegen] from `rustc_codegen_ssa`. The operands are lowered to LLVM operands and constraint codes as follows: -- `out` and the output part of `inout` operands are added first, as required by LLVM. Late output -operands have a `=` prefix added to their constraint code, non-late output operands have a `=&` -prefix added to their constraint code. +- `out` and the output part of `inout` operands are added first, as required by LLVM. + Late output operands have a `=` prefix added to their constraint code, + and non-late output operands have a `=&` prefix added to their constraint code. - `in` operands are added normally. - `inout` operands are tied to the matching output operand. -- `sym` operands are passed as function pointers or pointers, using the `"s"` constraint. +- `sym` operands are passed as function pointers or pointers, + using the `"s"` constraint. - `const` operands are formatted to a string and directly inserted in the template string. The template string is converted to LLVM form: - `$` characters are escaped as `$$`. - `const` operands are converted to strings and inserted directly. -- Placeholders are formatted as `${X:M}` where `X` is the operand index and `M` is the modifier -character. Modifiers are converted from the Rust form to the LLVM form. +- Placeholders are formatted as `${X:M}`, + where `X` is the operand index and `M` is the modifier character. + Modifiers are converted from the Rust form to the LLVM form. -The various options are converted to clobber constraints or LLVM attributes, refer to the -[RFC](https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-inline-asm.md#mapping-to-llvm-ir) -for more details. +The various options are converted to clobber constraints or LLVM attributes; +refer to the [RFC] for more details. Note that LLVM is sometimes rather picky about what types it accepts for certain constraint codes -so we sometimes need to insert conversions to/from a supported type. See the target-specific -ISelLowering.cpp files in LLVM for details of what types are supported for each register class. +so we sometimes need to insert conversions to/from a supported type. +See the target-specific ISelLowering.cpp files in LLVM +for details of what types are supported for each register class. [inline_asm_codegen]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/traits/enum.InlineAsmOperandRef.html +[RFC]: https://github.com/Amanieu/rfcs/blob/inline-asm/text/0000-inline-asm.md#mapping-to-llvm-ir ## Adding support for new architectures Adding inline assembly support to an architecture is mostly a matter of defining the registers and -register classes for that architecture. All the definitions for register classes are located in +register classes for that architecture. +All the definitions for register classes are located in `compiler/rustc_target/asm/`. Additionally you will need to implement lowering of these register classes to LLVM constraint codes in `compiler/rustc_codegen_llvm/asm.rs`. When adding a new architecture, make sure to cross-reference with the LLVM source code: -- LLVM has restrictions on which types can be used with a particular constraint code. Refer to the -`getRegForInlineAsmConstraint` function in `lib/Target/${ARCH}/${ARCH}ISelLowering.cpp`. -- LLVM reserves certain registers for its internal use, which causes them to not be saved/restored -properly around inline assembly blocks. These registers are listed in the `getReservedRegs` -function in `lib/Target/${ARCH}/${ARCH}RegisterInfo.cpp`. Any "conditionally" reserved register -such as the frame/base pointer must always be treated as reserved for Rust purposes because we -can't know ahead of time whether a function will require a frame/base pointer. +- LLVM has restrictions on which types can be used with a particular constraint code. + Refer to the `getRegForInlineAsmConstraint` function + in `lib/Target/${ARCH}/${ARCH}ISelLowering.cpp`. +- LLVM reserves certain registers for its internal use, + which causes them to not be saved/restored properly around inline assembly blocks. + These registers are listed in the `getReservedRegs` + function in `lib/Target/${ARCH}/${ARCH}RegisterInfo.cpp`. + Any "conditionally" reserved register, + such as the frame/base pointer, + must always be treated as reserved for Rust purposes because we + can't know ahead of time whether a function will require a frame/base pointer. ## Tests diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index 6b66a9dcb2d5f..648e6c0ccef6f 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -1,30 +1,36 @@ # Installation -In the near future, `std::autodiff` should become available for users via rustup. As a rustc/enzyme/autodiff contributor however, you will still need to build rustc from source. -For the meantime, you can download up-to-date builds to enable `std::autodiff` on your latest nightly toolchain, if you are using either of: -**Linux**, with `x86_64-unknown-linux-gnu` or `aarch64-unknown-linux-gnu` -**Windows**, with `x86_64-llvm-mingw` or `aarch64-llvm-mingw` +In the near future, `std::autodiff` should become available for users via rustup. +As a rustc/enzyme/autodiff contributor however, you will still need to build rustc from source. +For the meantime, you can download up-to-date builds to enable `std::autodiff` on your latest nightly toolchain, if you are using either of: +**Linux**, with `x86_64-unknown-linux-gnu` or `aarch64-unknown-linux-gnu` +**Windows**, with `x86_64-llvm-mingw` or `aarch64-llvm-mingw` -You can also download slightly outdated builds for **Apple** (aarch64-apple), which should generally work for now. +You can also download slightly outdated builds for **Apple** (aarch64-apple), which should generally work for now. -If you need any other platform, you can build rustc including autodiff from source. Please open an issue if you want to help enabling automatic builds for your prefered target. +If you need any other platform, you can build rustc including autodiff from source. +Please open an issue if you want to help enabling automatic builds for your prefered target. ## Installation guide -If you want to use `std::autodiff` and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. In the future, rustup will be able to do it for you. +If you want to use `std::autodiff` and don't plan to contribute PR's to the project, then we recommend to just use your existing nightly installation and download the missing component. +In the future, rustup will be able to do it for you. For now, you'll have to manually download and copy it. 1) On our github repository, find the last merged PR: [`Repo`] -2) Scroll down to the lower end of the PR, where you'll find a rust-bors message saying `Test successful` with a `CI` link. -3) Click on the `CI` link, and grep for your target. E.g. `dist-x86_64-linux` or `dist-aarch64-llvm-mingw` and click `Load summary`. +2) Scroll down to the lower end of the PR, where you'll find a rust-bors message saying `Test successful` with a `CI` link. +3) Click on the `CI` link, and grep for your target. E.g. `dist-x86_64-linux` or `dist-aarch64-llvm-mingw` and click `Load summary`. 4) Under the `CI artifacts` section, find the `enzyme-nightly` artifact, download, and unpack it. 5) Copy the artifact (libEnzyme-22.so for linux, libEnzyme-22.dylib for apple, etc.), which should be in a folder named `enzyme-preview`, to your rust toolchain directory. E.g. for linux: `cp ~/Downloads/enzyme-nightly-x86_64-unknown-linux-gnu/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib` -Apple support was temporarily reverted, due to downstream breakages. If you want to download autodiff for apple, please look at the artifacts from this [`run`]. +Apple support was temporarily reverted, due to downstream breakages. +If you want to download autodiff for apple, please look at the artifacts from this [`run`]. ## Installation guide for Nix user. -This setup was recommended by a nix and autodiff user. It uses [`Overlay`]. Please verify for yourself if you are comfortable using that repository. +This setup was recommended by a nix and autodiff user. +It uses [`Overlay`]. +Please verify for yourself if you are comfortable using that repository. In that case you might use the following nix configuration to get a rustc that supports `std::autodiff`. ```nix { @@ -32,7 +38,7 @@ In that case you might use the following nix configuration to get a rustc that s url = "https://ci-artifacts.rust-lang.org/rustc-builds/ec818fda361ca216eb186f5cf45131bd9c776bb4/enzyme-nightly-x86_64-unknown-linux-gnu.tar.xz"; sha256 = "sha256-Rnrop44vzS+qmYNaRoMNNMFyAc3YsMnwdNGYMXpZ5VY="; }; - + rustToolchain = pkgs.symlinkJoin { name = "rust-with-enzyme"; paths = [pkgs.rust-bin.nightly.latest.default]; @@ -48,27 +54,28 @@ In that case you might use the following nix configuration to get a rustc that s ## Build instructions -First you need to clone and configure the Rust repository. Based on your preferences, you might also want to `--enable-clang` or `--enable-lld`. -```bash +First you need to clone and configure the Rust repository. +Based on your preferences, you might also want to `--enable-clang` or `--enable-lld`. +```console git clone git@github.com:rust-lang/rust cd rust ./configure --release-channel=nightly --enable-llvm-enzyme --enable-llvm-link-shared --enable-llvm-assertions --enable-ninja --enable-option-checking --disable-docs --set llvm.download-ci-llvm=false ``` Afterwards you can build rustc using: -```bash +```console ./x build --stage 1 library ``` Afterwards rustc toolchain link will allow you to use it through cargo: -``` +```console rustup toolchain link enzyme build/host/stage1 rustup toolchain install nightly # enables -Z unstable-options ``` You can then run our test cases: -```bash +```console ./x test --stage 1 tests/codegen-llvm/autodiff ./x test --stage 1 tests/pretty/autodiff ./x test --stage 1 tests/ui/autodiff @@ -76,31 +83,35 @@ You can then run our test cases: ./x test --stage 1 tests/ui/feature-gates/feature-gate-autodiff.rs ``` -Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml -and use `RUSTFLAGS="-Zautodiff=Enable" cargo +enzyme` instead of `cargo` or `cargo +nightly`. +Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml +and use `RUSTFLAGS="-Zautodiff=Enable" cargo +enzyme` instead of `cargo` or `cargo +nightly`. ## Compiler Explorer and dist builds -Our compiler explorer instance can be updated to a newer rustc in a similar way. First, prepare a docker instance. -```bash +Our compiler explorer instance can be updated to a newer rustc in a similar way. +First, prepare a docker instance. +```console docker run -it ubuntu:22.04 export CC=clang CXX=clang++ apt update -apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmake clang build-essential +apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmake clang build-essential ``` Then build rustc in a slightly altered way: -```bash +```console git clone https://github.com/rust-lang/rust cd rust ./configure --release-channel=nightly --enable-llvm-enzyme --enable-llvm-link-shared --enable-llvm-assertions --enable-ninja --enable-option-checking --disable-docs --set llvm.download-ci-llvm=false ./x dist ``` -We then copy the tarball to our host. The dockerid is the newest entry under `docker ps -a`. -```bash +We then copy the tarball to our host. +The dockerid is the newest entry under `docker ps -a`. +```console docker cp :/rust/build/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz rust-nightly-x86_64-unknown-linux-gnu.tar.gz ``` Afterwards we can create a new (pre-release) tag on the EnzymeAD/rust repository and make a PR against the EnzymeAD/enzyme-explorer repository to update the tag. -Remember to ping `tgymnich` on the PR to run his update script. Note: We should archive EnzymeAD/rust and update the instructions here. The explorer should soon +Remember to ping `tgymnich` on the PR to run his update script. +Note: We should archive EnzymeAD/rust and update the instructions here. +The explorer should soon be able to get the rustc toolchain from the official rust servers. @@ -110,7 +121,7 @@ Following the Rust build instruction above will build LLVMEnzyme, LLDEnzyme, and We recommend that approach, if you just want to use any of them and have no experience with cmake. However, if you prefer to just build Enzyme without Rust, then these instructions might help. -```bash +```console git clone git@github.com:llvm/llvm-project cd llvm-project mkdir build @@ -121,15 +132,16 @@ ninja install ``` This gives you a working LLVM build, now we can continue with building Enzyme. Leave the `llvm-project` folder, and execute the following commands: -```bash +```console git clone git@github.com:EnzymeAD/Enzyme cd Enzyme/enzyme -mkdir build -cd build +mkdir build +cd build cmake .. -G Ninja -DLLVM_DIR=/llvm-project/build/lib/cmake/llvm/ -DLLVM_EXTERNAL_LIT=/llvm-project/llvm/utils/lit/lit.py -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=YES -DBUILD_SHARED_LIBS=ON ninja ``` -This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/Enzyme.so`. (Endings might differ based on your OS). +This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/Enzyme.so`. +(Endings might differ based on your OS). [`Repo`]: https://github.com/rust-lang/rust/ [`run`]: https://github.com/rust-lang/rust/pull/153026#issuecomment-3950046599 diff --git a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md index 2fdda4eda99a3..ad0dbb3aa9036 100644 --- a/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md +++ b/src/doc/rustc-dev-guide/src/backend/backend-agnostic.md @@ -1,15 +1,13 @@ # Backend Agnostic Codegen -[`rustc_codegen_ssa`] -provides an abstract interface for all backends to implement, +[`rustc_codegen_ssa`] provides an abstract interface for all backends to implement, namely LLVM, [Cranelift], and [GCC]. [Cranelift]: https://github.com/rust-lang/rustc_codegen_cranelift [GCC]: https://github.com/rust-lang/rustc_codegen_gcc [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html -Below is some background information on the refactoring that created this -abstract interface. +Below is some background information on the refactoring that created this abstract interface. ## Refactoring of `rustc_codegen_llvm` by Denis Merigoux, October 23rd 2018 @@ -17,17 +15,15 @@ by Denis Merigoux, October 23rd 2018 ### State of the code before the refactoring All the code related to the compilation of MIR into LLVM IR was contained -inside the `rustc_codegen_llvm` crate. Here is the breakdown of the most -important elements: +inside the `rustc_codegen_llvm` crate. +Here is the breakdown of the most important elements: * the `back` folder (7,800 LOC) implements the mechanisms for creating the different object files and archive through LLVM, but also the communication mechanisms for parallel code generation; -* the `debuginfo` (3,200 LOC) folder contains all code that passes debug - information down to LLVM; +* the `debuginfo` (3,200 LOC) folder contains all code that passes debug information down to LLVM; * the `llvm` (2,200 LOC) folder defines the FFI necessary to communicate with LLVM using the C++ API; -* the `mir` (4,300 LOC) folder implements the actual lowering from MIR to LLVM - IR; +* the `mir` (4,300 LOC) folder implements the actual lowering from MIR to LLVM IR; * the `base.rs` (1,300 LOC) file contains some helper functions but also the high-level code that launches the code generation and distributes the work. * the `builder.rs` (1,200 LOC) file contains all the functions generating @@ -37,33 +33,33 @@ important elements: * the `type_.rs` (300 LOC) defines most of the type translations to LLVM IR. The goal of this refactoring is to separate inside this crate code that is -specific to the LLVM from code that can be reused for other rustc backends. For -instance, the `mir` folder is almost entirely backend-specific but it relies -heavily on other parts of the crate. The separation of the code must not affect -the logic of the code nor its performance. +specific to LLVM from code that can be reused for other rustc backends. +For instance, +the `mir` folder is almost entirely backend-specific, +but it relies heavily on other parts of the crate. +The separation of the code must not affect the logic of the code, +nor its performance. For these reasons, the separation process involves two transformations that have to be done at the same time for the resulting code to compile: -1. replace all the LLVM-specific types by generics inside function signatures - and structure definitions; -2. encapsulate all functions calling the LLVM FFI inside a set of traits that - will define the interface between backend-agnostic code and the backend. +1. Replace all LLVM-specific types by generics inside function signatures + and structure definitions +2. Encapsulate all functions calling the LLVM FFI inside a set of traits that + will define the interface between backend-agnostic code and the backend -While the LLVM-specific code will be left in `rustc_codegen_llvm`, all the new -traits and backend-agnostic code will be moved in `rustc_codegen_ssa` (name -suggestion by @eddyb). +While LLVM-specific code will be left in `rustc_codegen_llvm`, all the new +traits and backend-agnostic code will be moved in `rustc_codegen_ssa` (name suggestion by @eddyb). ### Generic types and structures @irinagpopa started to parametrize the types of `rustc_codegen_llvm` by a -generic `Value` type, implemented in LLVM by a reference `&'ll Value`. This -work has been extended to all structures inside the `mir` folder and elsewhere, +generic `Value` type, implemented in LLVM by a reference `&'ll Value`. +This work has been extended to all structures inside the `mir` folder and elsewhere, as well as for LLVM's `BasicBlock` and `Type` types. -The two most important structures for the LLVM codegen are `CodegenCx` and -`Builder`. They are parametrized by multiple lifetime parameters and the type -for `Value`. +The two most important structures for the LLVM codegen are `CodegenCx` and `Builder`. +They are parametrized by multiple lifetime parameters and the type for `Value`. ```rust,ignore struct CodegenCx<'ll, 'tcx> { @@ -83,10 +79,8 @@ The code in `rustc_codegen_llvm` has to deal with multiple explicit lifetime parameters, that correspond to the following: * `'tcx` is the longest lifetime, that corresponds to the original `TyCtxt` containing the program's information; -* `'a` is a short-lived reference of a `CodegenCx` or another object inside a - struct; -* `'ll` is the lifetime of references to LLVM objects such as `Value` or - `Type`. +* `'a` is a short-lived reference of a `CodegenCx` or another object inside a struct; +* `'ll` is the lifetime of references to LLVM objects such as `Value` or `Type`. Although there are already many lifetime parameters in the code, making it generic uncovered situations where the borrow-checker was passing only due to @@ -100,19 +94,20 @@ struct LocalAnalyzer<'mir, 'a, 'tcx> { } ``` -However, the two most important structures `CodegenCx` and `Builder` are not -defined in the backend-agnostic code. Indeed, their content is highly specific -of the backend and it makes more sense to leave their definition to the backend -implementor than to allow just a narrow spot via a generic field for the -backend's context. +However, the two most important structures, +`CodegenCx` and `Builder`, +are not defined in the backend-agnostic code. +Indeed, their content is highly specific to the backend, +and it makes more sense to leave their definition to the backend +implementor than to allow just a narrow spot via a generic field for the backend's context. ### Traits and interface Because they have to be defined by the backend, `CodegenCx` and `Builder` will be the structures implementing all the traits defining the backend's interface. These traits are defined in the folder `rustc_codegen_ssa/traits` and all the -backend-agnostic code is parametrized by them. For instance, let us explain how -a function in `base.rs` is parametrized: +backend-agnostic code is parametrized by them. +For instance, let us explain how a function in `base.rs` is parametrized: ```rust,ignore pub fn codegen_instance<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( @@ -125,9 +120,10 @@ pub fn codegen_instance<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( In this signature, we have the two lifetime parameters explained earlier and the master type `Bx` which satisfies the trait `BuilderMethods` corresponding -to the interface satisfied by the `Builder` struct. The `BuilderMethods` -defines an associated type `Bx::CodegenCx` that itself satisfies the -`CodegenMethods` traits implemented by the struct `CodegenCx`. +to the interface satisfied by the `Builder` struct. +The `BuilderMethods` defines an associated type, `Bx::CodegenCx`, +that itself satisfies the `CodegenMethods` traits implemented by the struct, +`CodegenCx`. On the trait side, here is an example with part of the definition of `BuilderMethods` in `traits/builder.rs`: @@ -158,27 +154,27 @@ pub trait BuilderMethods<'a, 'tcx>: ``` Finally, a master structure implementing the `ExtraBackendMethods` trait is -used for high-level codegen-driving functions like `codegen_crate` in -`base.rs`. For LLVM, it is the empty `LlvmCodegenBackend`. +used for high-level codegen-driving functions like `codegen_crate` in `base.rs`. +For LLVM, it is the empty `LlvmCodegenBackend`. `ExtraBackendMethods` should be implemented by the same structure that -implements the `CodegenBackend` defined in -`rustc_codegen_utils/codegen_backend.rs`. +implements the `CodegenBackend` defined in `rustc_codegen_ssa/src/traits/backend.rs`. During the traitification process, certain functions have been converted from methods of a local structure to methods of `CodegenCx` or `Builder` and a -corresponding `self` parameter has been added. Indeed, LLVM stores information -internally that it can access when called through its API. This information -does not show up in a Rust data structure carried around when these methods are -called. However, when implementing a Rust backend for `rustc`, these methods +corresponding `self` parameter has been added. +Indeed, LLVM stores information internally that it can access when called through its API. +This information does not show up in a Rust data structure carried around when these methods are +called. +However, when implementing a Rust backend for `rustc`, these methods will need information from `CodegenCx`, hence the additional parameter (unused in the LLVM implementation of the trait). ### State of the code after the refactoring -The traits offer an API which is very similar to the API of LLVM. This is not -the best solution since LLVM has a very special way of doing things: when -adding another backend, the traits definition might be changed in order to -offer more flexibility. +The traits offer an API which is very similar to the API of LLVM. +This is not the best solution since LLVM has a very special way of doing things: +when adding another backend, +the traits definition might be changed in order to offer more flexibility. However, the current separation between backend-agnostic and LLVM-specific code has allowed the reuse of a significant part of the old `rustc_codegen_llvm`. @@ -191,17 +187,17 @@ most important elements: * `builder.rs`: 1,400 (BA) vs 0 (LLVM); * `common.rs`: 350 (BA) vs 350 (LLVM); -The `debuginfo` folder has been left almost untouched by the splitting and is -specific to LLVM. Only its high-level features have been traitified. +The `debuginfo` folder has been left almost untouched by the splitting and is specific to LLVM. +Only its high-level features have been traitified. -The new `traits` folder has 1500 LOC only for trait definitions. Overall, the -27,000 LOC-sized old `rustc_codegen_llvm` code has been split into the new -18,500 LOC-sized new `rustc_codegen_llvm` and the 12,000 LOC-sized -`rustc_codegen_ssa`. We can say that this refactoring allowed the reuse of +The new `traits` folder has 1500 LOC only for trait definitions. +Overall, +the 27,000 LOC-sized old `rustc_codegen_llvm` code has been split into the new +18,500 LOC-sized new `rustc_codegen_llvm` and the 12,000 LOC-sized `rustc_codegen_ssa`. +We can say that this refactoring allowed the reuse of approximately 10,000 LOC that would otherwise have had to be duplicated between the multiple backends of `rustc`. The refactored version of `rustc`'s backend introduced no regression over the test suite nor in performance benchmark, which is in coherence with the nature -of the refactoring that used only compile-time parametricity (no trait -objects). +of the refactoring that used only compile-time parametricity (no trait objects). diff --git a/src/doc/rustc-dev-guide/src/building/prerequisites.md b/src/doc/rustc-dev-guide/src/building/prerequisites.md index d984cc4e391d4..4833d34412022 100644 --- a/src/doc/rustc-dev-guide/src/building/prerequisites.md +++ b/src/doc/rustc-dev-guide/src/building/prerequisites.md @@ -6,35 +6,44 @@ See [the `rust-lang/rust` INSTALL](https://github.com/rust-lang/rust/blob/HEAD/I ## Hardware -You will need an internet connection to build. The bootstrapping process -involves updating git submodules and downloading a beta compiler. It doesn't -need to be super fast, but that can help. +You will need an internet connection to build. +The bootstrapping process +involves updating git submodules and downloading a beta compiler. +It doesn't need to be super fast, but that can help. There are no strict hardware requirements, but building the compiler is computationally expensive, so a beefier machine will help, and I wouldn't -recommend trying to build on a Raspberry Pi! We recommend the following. -* 30GB+ of free disk space. Otherwise, you will have to keep - clearing incremental caches. More space is better, the compiler is a bit of a +recommend trying to build on a Raspberry Pi! +We recommend the following. +* 30GB+ of free disk space. + Otherwise, you will have to keep clearing incremental caches. + More space is better, the compiler is a bit of a hog; it's a problem we are aware of. * 8GB+ RAM -* 2+ cores. Having more cores really helps. 10 or 20 or more is not too many! +* 2+ cores. + Having more cores really helps. + 10 or 20 or more is not too many! -Beefier machines will lead to much faster builds. If your machine is not very -powerful, a common strategy is to only use `./x check` on your local machine +Beefier machines will lead to much faster builds. +If your machine is not very powerful, +a common strategy is to only use `./x check` on your local machine and let the CI build test your changes when you push to a PR branch. -Building the compiler takes more than half an hour on my moderately powerful -laptop. We suggest downloading LLVM from CI so you don't have to build it from source +Building the compiler takes more than half an hour on a moderately powerful +laptop. +We suggest downloading LLVM from CI so you don't have to build it from source ([see here][config]). -Like `cargo`, the build system will use as many cores as possible. Sometimes -this can cause you to run low on memory. You can use `-j` to adjust the number -of concurrent jobs. If a full build takes more than ~45 minutes to an hour, you +Like `cargo`, the build system will use as many cores as possible. +Sometimes this can cause you to run low on memory. +You can use `-j` to adjust the number of concurrent jobs. +If a full build takes more than ~45 minutes to an hour, you are probably spending most of the time swapping memory in and out; try using `-j1`. If you don't have too much free disk space, you may want to turn off -incremental compilation ([see here][config]). This will make compilation take +incremental compilation ([see here][config]). +This will make compilation take longer (especially after a rebase), but will save a ton of space from the incremental caches. diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index d9921cbb133ea..c8b25edc1e532 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -154,9 +154,10 @@ For Neovim users, there are a few options: #### neoconf.nvim [neoconf.nvim][neoconf.nvim] allows for project-local configuration -files with the native LSP. The steps for how to use it are below. Note that they require -rust-analyzer to already be configured with Neovim. Steps for this can be -[found here][r-a nvim lsp]. +files with the native LSP. +The steps for how to use it are below. +Note that they require rust-analyzer to already be configured with Neovim. +Steps for this can be [found here][r-a nvim lsp]. 1. First install the plugin. This can be done by following the steps in the README. diff --git a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md index e6984417086d8..bd1ec6e9b1ef9 100644 --- a/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md +++ b/src/doc/rustc-dev-guide/src/debugging-support-in-rustc.md @@ -247,7 +247,7 @@ The steps of this process are as follows: 1. LLVM needs changing. - LLVM does not emit Interface types at all, so this needs to be implemented in the LLVM first. + LLVM does not emit Interface types at all, so this needs to be implemented in LLVM first. Get sign off on LLVM maintainers that this is a good idea. diff --git a/src/doc/rustc-dev-guide/src/mir/construction.md b/src/doc/rustc-dev-guide/src/mir/construction.md index 8360d9ff1a8bc..b9b5f0a346416 100644 --- a/src/doc/rustc-dev-guide/src/mir/construction.md +++ b/src/doc/rustc-dev-guide/src/mir/construction.md @@ -11,15 +11,17 @@ list of items: * Drop code (the `Drop::drop` function is not called directly) * Drop implementations of types without an explicit `Drop` implementation -The lowering is triggered by calling the [`mir_built`] query. The MIR builder does -not actually use the HIR but operates on the [THIR] instead, processing THIR -expressions recursively. +The lowering is triggered by calling the [`mir_built`] query. +The MIR builder does not actually use the HIR, +but operates on the [THIR] instead, +processing THIR expressions recursively. The lowering creates local variables for every argument as specified in the signature. Next, it creates local variables for every binding specified (e.g. `(a, b): (i32, String)`) -produces 3 bindings, one for the argument, and two for the bindings. Next, it generates -field accesses that read the fields from the argument and writes the value to the binding -variable. +produces 3 bindings, one for the argument, and two for the bindings. +Next, +it generates field accesses that read the fields from the argument, +and writes the value to the binding variable. With this initialization out of the way, the lowering triggers a recursive call to a function that generates the MIR for the body (a `Block` expression) and @@ -52,7 +54,8 @@ fn generate_more_mir(&mut self, block: BasicBlock) -> BlockAnd { ``` When you invoke these functions, it is common to have a local variable `block` -that is effectively a "cursor". It represents the point at which we are adding new MIR. +that is effectively a "cursor". +It represents the point at which we are adding new MIR. When you invoke `generate_more_mir`, you want to update this cursor. You can do this manually, but it's tedious: @@ -89,10 +92,12 @@ representations: We start out with lowering the function body to an `Rvalue` so we can create an assignment to `RETURN_PLACE`, This `Rvalue` lowering will in turn trigger lowering to -`Operand` for its arguments (if any). `Operand` lowering either produces a `const` -operand, or moves/copies out of a `Place`, thus triggering a `Place` lowering. An -expression being lowered to a `Place` can in turn trigger a temporary to be created -if the expression being lowered contains operations. This is where the snake bites its +`Operand` for its arguments (if any). +`Operand` lowering either produces a `const` operand, +or moves/copies out of a `Place`, thus triggering a `Place` lowering. +An expression being lowered to a `Place` can in turn trigger a temporary to be created +if the expression being lowered contains operations. +This is where the snake bites its own tail and we need to trigger an `Rvalue` lowering for the expression to be written into the local. @@ -100,7 +105,8 @@ into the local. Operators on builtin types are not lowered to function calls (which would end up being infinite recursion calls, because the trait impls just contain the operation itself -again). Instead there are `Rvalue`s for binary and unary operators and index operations. +again). +Instead there are `Rvalue`s for binary and unary operators and index operations. These `Rvalue`s later get codegened to llvm primitive operations or llvm intrinsics. Operators on all other types get lowered to a function call to their `impl` of the @@ -118,7 +124,8 @@ In [MIR] there is no difference between method calls and function calls anymore. ## Conditions `if` conditions and `match` statements for `enum`s with variants that have no fields are -lowered to `TerminatorKind::SwitchInt`. Each possible value (so `0` and `1` for `if` +lowered to `TerminatorKind::SwitchInt`. +Each possible value (so `0` and `1` for `if` conditions) has a corresponding `BasicBlock` to which the code continues. The argument being branched on is (again) an `Operand` representing the value of the if condition. @@ -127,14 +134,14 @@ the if condition. `match` statements for `enum`s with variants that have fields are lowered to `TerminatorKind::SwitchInt`, too, but the `Operand` refers to a `Place` where the -discriminant of the value can be found. This often involves reading the discriminant -to a new temporary variable. +discriminant of the value can be found. +This often involves reading the discriminant to a new temporary variable. ## Aggregate construction Aggregate values of any kind (e.g. structs or tuples) are built via `Rvalue::Aggregate`. -All fields are -lowered to `Operator`s. This is essentially equivalent to one assignment +All fields are lowered to `Operator`s. +This is essentially equivalent to one assignment statement per aggregate field plus an assignment to the discriminant in the case of `enum`s. diff --git a/src/doc/rustc-dev-guide/src/name-resolution.md b/src/doc/rustc-dev-guide/src/name-resolution.md index 79d0897b4279e..83d2996420507 100644 --- a/src/doc/rustc-dev-guide/src/name-resolution.md +++ b/src/doc/rustc-dev-guide/src/name-resolution.md @@ -62,8 +62,7 @@ files and expanding `macros`. This phase produces links from all the names in the source to relevant places where the name was introduced. It also generates helpful error messages, -like typo suggestions, traits to import or lints about -unused items. +like typo suggestions, traits to import, or lints about unused items. A successful run of the second phase ([`Resolver::resolve_crate`]) creates kind of an index the rest of the compilation may use to ask about the present names diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md index 28c836dc4dba2..8d5b7d1278307 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/about.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md @@ -22,6 +22,7 @@ Here's the list of the notification groups: - [Apple](./apple.md) - [ARM](./arm.md) - [Emscripten](./emscripten.md) +- [Fuchsia](./fuchsia.md) - [LoongArch](./loongarch.md) - [RISC-V](./risc-v.md) - [WASI](./wasi.md) diff --git a/src/doc/rustc-dev-guide/src/offload/contributing.md b/src/doc/rustc-dev-guide/src/offload/contributing.md index f3a1ed2150a1b..5211bdf4303d9 100644 --- a/src/doc/rustc-dev-guide/src/offload/contributing.md +++ b/src/doc/rustc-dev-guide/src/offload/contributing.md @@ -1,8 +1,13 @@ # Contributing -Contributions are always welcome. This project is experimental, so the documentation and code are likely incomplete. Please ask on [Zulip](https://rust-lang.zulipchat.com/#narrow/channel/422870-t-compiler.2Fgpgpu-backend) (preferred) or the Rust Community Discord for help if you get stuck or if our documentation is unclear. +Contributions are always welcome. +This project is experimental, so the documentation and code are likely incomplete. +Please ask on [Zulip](https://rust-lang.zulipchat.com/#narrow/channel/422870-t-compiler.2Fgpgpu-backend) (preferred) or the Rust Community Discord for help if you get stuck or if our documentation is unclear. -We generally try to automate as much of the compilation process as possible for users. However, as a contributor it might sometimes be easier to directly rewrite and compile the LLVM-IR modules (.ll) to quickly iterate on changes, without needing to repeatedly recompile rustc. For people familiar with LLVM we therefore have the shell script below. Only when you are then happy with the IR changes you can work on updating rustc to generate the new, desired output. +We generally try to automate as much of the compilation process as possible for users. +However, as a contributor it might sometimes be easier to directly rewrite and compile the LLVM-IR modules (.ll) to quickly iterate on changes, without needing to repeatedly recompile rustc. +For people familiar with LLVM we therefore have the shell script below. +Only when you are then happy with the IR changes you can work on updating rustc to generate the new, desired output. ```sh set -e @@ -29,4 +34,6 @@ opt lib.ll -o lib.bc LIBOMPTARGET_INFO=-1 OFFLOAD_TRACK_ALLOCATION_TRACES=true ./a.out ``` -Please update the `` placeholders on the `clang-linker-wrapper` invocation. You will likely also need to adjust the library paths. See the linked usage section for details: [usage](usage.md#compile-instructions) +Please update the `` placeholders on the `clang-linker-wrapper` invocation. +You will likely also need to adjust the library paths. +See the linked usage section for details: [usage](usage.md#compile-instructions) diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index ac852e01f313f..00233d9b02f8f 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -1,23 +1,24 @@ # Installation -`std::offload` is partly available in nightly builds for users. For now, everyone however still needs to build rustc from source to use all features of it. +`std::offload` is partly available in nightly builds for users. +For now, everyone however still needs to build rustc from source to use all features of it. ## Build instructions First you need to clone and configure the Rust repository: -```bash +```console git clone git@github.com:rust-lang/rust cd rust ./configure --enable-llvm-link-shared --release-channel=nightly --enable-llvm-assertions --enable-llvm-offload --enable-llvm-enzyme --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs ``` Afterwards you can build rustc using: -```bash +```console ./x build --stage 1 library ``` Afterwards rustc toolchain link will allow you to use it through cargo: -``` +```console rustup toolchain link offload build/host/stage1 rustup toolchain install nightly # enables -Z unstable-options ``` @@ -25,7 +26,7 @@ rustup toolchain install nightly # enables -Z unstable-options ## Build instruction for LLVM itself -```bash +```console git clone git@github.com:llvm/llvm-project cd llvm-project mkdir build @@ -39,6 +40,6 @@ This gives you a working LLVM build. ## Testing run -``` +```console ./x test --stage 1 tests/codegen-llvm/gpu_offload ``` diff --git a/src/doc/rustc-dev-guide/src/offload/internals.md b/src/doc/rustc-dev-guide/src/offload/internals.md index 836fd7ad2670b..78a1a852d21b3 100644 --- a/src/doc/rustc-dev-guide/src/offload/internals.md +++ b/src/doc/rustc-dev-guide/src/offload/internals.md @@ -1,22 +1,47 @@ # std::offload -This module is under active development. Once upstream, it should allow Rust developers to run Rust code on GPUs. +This module is under active development. +Once upstream, it should allow Rust developers to run Rust code on GPUs. We aim to develop a `rusty` GPU programming interface, which is safe, convenient and sufficiently fast by default. -This includes automatic data movement to and from the GPU, in a efficient way. We will (later) -also offer more advanced, possibly unsafe, interfaces which allow a higher degree of control. +This includes automatic data movement to and from the GPU, in a efficient way. +We will (later) also offer more advanced, +possibly unsafe, interfaces which allow a higher degree of control. -The implementation is based on LLVM's "offload" project, which is already used by OpenMP to run Fortran or C++ code on GPUs. -While the project is under development, users will need to call other compilers like clang to finish the compilation process. +The implementation is based on LLVM's "offload" project, +which is already used by OpenMP to run Fortran or C++ code on GPUs. +While the project is under development, +users will need to call other compilers like clang to finish the compilation process. ## High-level compilation design: -We use a single-source, two-pass compilation approach. - -First we compile all functions that should be offloaded for the device (e.g nvptx64, amdgcn-amd-amdhsa, intel in the future). Currently we require cumbersome `#cfg(target_os="")` annotations, but we intend to recognize those in the future based on our offload intrinsic. -This first compilation currently does not leverage rustc's internal Query system, so it will always recompile your kernels at the moment. This should be easy to fix, but we prioritize features and runtime performance improvements at the moment. Please reach out if you want to implement it, though! - -We then compile the code for the host (e.g. x86-64), where most of the offloading logic happens. On the host side, we generate calls to the openmp offload runtime, to inform it about the layout of the types (a simplified version of the autodiff TypeTrees). We also use the type system to figure out whether kernel arguments have to be moved only to the device (e.g. `&[f32;1024]`), from the device, or both (e.g. `&mut [f64]`). We then launch the kernel, after which we inform the runtime to end this environment and move data back (as far as needed). - -The second pass for the host will load the kernel artifacts from the previous compilation. rustc in general may not "guess" or hardcode the build directory layout, and as such it must be told the path to the kernel artifacts in the second invocation. The logic for this could be integrated into cargo, but it also only requires a trivial cargo wrapper, which we could trivially provide via crates.io till we see larger adoption. - -It might seem tempting to think about a single-source, single pass compilation approach. However, a lot of the rustc frontend (e.g. AST) will drop any dead code (e.g. code behind an inactive `cfg`). Getting the frontend to expand and lower code for two targets naively will result in multiple definitions of the same symbol (and other issues). Trying to teach the whole rustc middle and backend to be aware that any symbol now might contain two implementations is a large undertaking, and it is questionable why we should make the whole compiler more complex, if the alternative is a ~5 line cargo wrapper. We still control the full compilation pipeline and have both host and device code available, therefore there shouldn't be a runtime performance difference between the two approaches. +We use a single-source, two-pass compilation approach. + +First we compile all functions that should be offloaded for the device +(e.g nvptx64, amdgcn-amd-amdhsa, intel in the future). +Currently we require cumbersome `#cfg(target_os="")` annotations, but we intend to recognize those in the future based on our offload intrinsic. +This first compilation currently does not leverage rustc's internal Query system, so it will always recompile your kernels at the moment. +This should be easy to fix, but we prioritize features and runtime performance improvements at the moment. +Please reach out if you want to implement it, though! + +We then compile the code for the host (e.g. x86-64), where most of the offloading logic happens. +On the host side, we generate calls to the openmp offload runtime, +to inform it about the layout of the types (a simplified version of the autodiff TypeTrees). +We also use the type system to figure out whether kernel arguments have to be moved only to the device (e.g. `&[f32;1024]`), +from the device, or both (e.g. `&mut [f64]`). +We then launch the kernel, +after which we inform the runtime to end this environment and move data back (as far as needed). + +The second pass for the host will load the kernel artifacts from the previous compilation. +rustc in general may not "guess" or hardcode the build directory layout, +and as such it must be told the path to the kernel artifacts in the second invocation. +The logic for this could be integrated into cargo, +but it also only requires a trivial cargo wrapper, +which we could trivially provide via crates.io till we see larger adoption. + +It might seem tempting to think about a single-source, single pass compilation approach. +However, a lot of the rustc frontend (e.g. AST) will drop any dead code (e.g. code behind an inactive `cfg`). +Getting the frontend to expand and lower code for two targets naively will result in multiple definitions of the same symbol (and other issues). +Trying to teach the whole rustc middle and backend to be aware that any symbol now might contain two implementations is a large undertaking, +and it is questionable why we should make the whole compiler more complex, if the alternative is a ~5 line cargo wrapper. +We still control the full compilation pipeline and have both host and device code available, +therefore there shouldn't be a runtime performance difference between the two approaches. diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index 4d3222123aaff..c7ce2ded42e97 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -1,7 +1,9 @@ # Usage -This feature is work-in-progress, and not ready for usage. The instructions here are for contributors, or people interested in following the latest progress. -We currently work on launching the following Rust kernel on the GPU. To follow along, copy it to a `src/lib.rs` file. +This feature is work-in-progress, and not ready for usage. +The instructions here are for contributors, or people interested in following the latest progress. +We currently work on launching the following Rust kernel on the GPU. +To follow along, copy it to a `src/lib.rs` file. ```rust #![feature(abi_gpu_kernel)] @@ -75,9 +77,12 @@ pub extern "gpu-kernel" fn kernel_1(x: *mut [f64; 256]) { ``` ## Compile instructions -It is important to use a clang compiler build on the same llvm as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. +It is important to use a clang compiler build on the same llvm as rustc. +Just calling clang without the full path will likely use your system clang, which probably will be incompatible. +So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. -First we generate the device (gpu) code. Replace the target-cpu with the right code for your gpu. +First we generate the device (gpu) code. +Replace the target-cpu with the right code for your gpu. ``` RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core ``` @@ -94,8 +99,11 @@ While we integrated most offload steps into rustc by now, one binary invocation "clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "target//release/host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" ``` -You can try to find the paths to those files on your system. However, I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. -It will show multiple steps, just look for the clang-linker-wrapper example. Make sure to still include the path to the `host.o` file, and not whatever tmp file you got when compiling your c++ example with the following call. +You can try to find the paths to those files on your system. +However, I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. +By adding `-###` to your clang invocation, you can see the invidual steps. +It will show multiple steps, just look for the clang-linker-wrapper example. +Make sure to still include the path to the `host.o` file, and not whatever tmp file you got when compiling your c++ example with the following call. ``` myclang++ -fuse-ld=lld -O3 -fopenmp -fopenmp-offload-mandatory --offload-arch=gfx90a omp_bare.cpp -o main -### ``` diff --git a/src/doc/rustc-dev-guide/src/panic-implementation.md b/src/doc/rustc-dev-guide/src/panic-implementation.md index ea71abff19998..5101556941dc3 100644 --- a/src/doc/rustc-dev-guide/src/panic-implementation.md +++ b/src/doc/rustc-dev-guide/src/panic-implementation.md @@ -3,13 +3,13 @@ ## Step 1: Invocation of the `panic!` macro. There are actually two panic macros - one defined in `core`, and one defined in `std`. -This is due to the fact that code in `core` can panic. `core` is built before `std`, -but we want panics to use the same machinery at runtime, whether they originate in `core` -or `std`. +This is due to the fact that code in `core` can panic. +`core` is built before `std`, +but we want panics to use the same machinery at runtime, whether they originate in `core` or `std`. ### core definition of panic! -The `core` `panic!` macro eventually makes the following call (in `library/core/src/panicking.rs`): +The `core` `panic!` macro eventually makes the following call (in [`library/core/src/panicking.rs`]): ```rust // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call @@ -18,75 +18,88 @@ extern "Rust" { fn panic_impl(pi: &PanicInfo<'_>) -> !; } -let pi = PanicInfo::internal_constructor(Some(&fmt), location); +let pi = PanicInfo::new( + &fmt, + Location::caller(), + /* can_unwind */ true, + /* force_no_backtrace */ false, +); unsafe { panic_impl(&pi) } ``` Actually resolving this goes through several layers of indirection: -1. In `compiler/rustc_middle/src/middle/weak_lang_items.rs`, `panic_impl` is - declared as 'weak lang item', with the symbol `rust_begin_unwind`. This is - used in `rustc_hir_analysis/src/collect.rs` to set the actual symbol name to +1. In [`compiler/rustc_hir/src/weak_lang_items.rs`], `panic_impl` is + declared as 'weak lang item', with the symbol `rust_begin_unwind`. + This is used in `rustc_hir_analysis/src/collect.rs` to set the actual symbol name to `rust_begin_unwind`. Note that `panic_impl` is declared in an `extern "Rust"` block, which means that core will attempt to call a foreign symbol called `rust_begin_unwind` (to be resolved at link time) -2. In `library/std/src/panicking.rs`, we have this definition: +2. In [`library/std/src/panicking.rs`], we have this definition: ```rust -/// Entry point of panic from the core crate. -#[cfg(not(test))] +/// Entry point of panics from the core crate (`panic_impl` lang item). +#[cfg(not(any(test, doctest)))] #[panic_handler] -#[unwind(allowed)] -pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { +pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { ... } ``` -The special `panic_handler` attribute is resolved via `compiler/rustc_middle/src/middle/lang_items`. -The `extract` function converts the `panic_handler` attribute to a `panic_impl` lang item. +The special `panic_handler` attribute is resolved via [`compiler/rustc_passes/src/lang_items.rs`]. +The [`extract_ast`] function converts the `panic_handler` attribute to a `panic_impl` lang item. -Now, we have a matching `panic_handler` lang item in the `std`. This function goes +Now, we have a matching `panic_handler` lang item in the `std`. +This function goes through the same process as the `extern { fn panic_impl }` definition in `core`, ending -up with a symbol name of `rust_begin_unwind`. At link time, the symbol reference in `core` -will be resolved to the definition of `std` (the function called `begin_panic_handler` in the +up with a symbol name of `rust_begin_unwind`. +At link time, the symbol reference in `core` +will be resolved to the definition of `std` (the function called `panic_handler` in the Rust source). -Thus, control flow will pass from core to std at runtime. This allows panics from `core` +Thus, control flow will pass from core to std at runtime. +This allows panics from `core` to go through the same infrastructure that other panics use (panic hooks, unwinding, etc) ### std implementation of panic! -This is where the actual panic-related logic begins. In `library/std/src/panicking.rs`, -control passes to `rust_panic_with_hook`. This method is responsible -for invoking the global panic hook, and checking for double panics. Finally, +This is where the actual panic-related logic begins. +In [`library/std/src/panicking.rs`], +control passes to `panic_with_hook`. +This method is responsible for invoking the global panic hook, and checking for double panics. +Finally, we call `__rust_start_panic`, which is provided by the panic runtime. The call to `__rust_start_panic` is very weird - it is passed a `*mut &mut dyn PanicPayload`, -converted to an `usize`. Let's break this type down: +converted to an `usize`. +Let's break this type down: -1. `PanicPayload` is an internal trait. It is implemented for `PanicPayload` -(a wrapper around the user-supplied payload type), and has a method -`fn take_box(&mut self) -> *mut (dyn Any + Send)`. -This method takes the user-provided payload (`T: Any + Send`), -boxes it, and converts the box to a raw pointer. +1. `PanicPayload` is an internal trait. + It is implemented for `PanicPayload` + (a wrapper around the user-supplied payload type), and has a method + `fn take_box(&mut self) -> *mut (dyn Any + Send)`. + This method takes the user-provided payload (`T: Any + Send`), + boxes it, and converts the box to a raw pointer. 2. When we call `__rust_start_panic`, we have an `&mut dyn PanicPayload`. -However, this is a fat pointer (twice the size of a `usize`). -To pass this to the panic runtime across an FFI boundary, we take a mutable -reference *to this mutable reference* (`&mut &mut dyn PanicPayload`), and convert it to a raw -pointer (`*mut &mut dyn PanicPayload`). The outer raw pointer is a thin pointer, since it points to -a `Sized` type (a mutable reference). Therefore, we can convert this thin pointer into a `usize`, -which is suitable for passing across an FFI boundary. + However, this is a fat pointer (twice the size of a `usize`). + To pass this to the panic runtime across an FFI boundary, we take a mutable + reference *to this mutable reference* (`&mut &mut dyn PanicPayload`), and convert it to a raw + pointer (`*mut &mut dyn PanicPayload`). + The outer raw pointer is a thin pointer, since it points to a `Sized` type (a mutable reference). + Therefore, we can convert this thin pointer into a `usize`, + which is suitable for passing across an FFI boundary. -Finally, we call `__rust_start_panic` with this `usize`. We have now entered the panic runtime. +Finally, we call `__rust_start_panic` with this `usize`. +We have now entered the panic runtime. ## Step 2: The panic runtime -Rust provides two panic runtimes: `panic_abort` and `panic_unwind`. The user chooses -between them at build time via their `Cargo.toml` +Rust provides two panic runtimes: `panic_abort` and `panic_unwind`. +The user chooses between them at build time via their `Cargo.toml` `panic_abort` is extremely simple: its implementation of `__rust_start_panic` just aborts, as you would expect. @@ -95,13 +108,14 @@ as you would expect. In its implementation of `__rust_start_panic`, we take the `usize`, convert it back to a `*mut &mut dyn PanicPayload`, dereference it, and call `take_box` -on the `&mut dyn PanicPayload`. At this point, we have a raw pointer to the payload +on the `&mut dyn PanicPayload`. +At this point, we have a raw pointer to the payload itself (a `*mut (dyn Send + Any)`): that is, a raw pointer to the actual value provided by the user who called `panic!`. -At this point, the platform-independent code ends. We now call into -platform-specific unwinding logic (e.g `unwind`). This code is -responsible for unwinding the stack, running any 'landing pads' associated +At this point, the platform-independent code ends. +We now call into platform-specific unwinding logic (e.g `unwind`). +This code is responsible for unwinding the stack, running any 'landing pads' associated with each frame (currently, running destructors), and transferring control to the `catch_unwind` frame. @@ -109,5 +123,9 @@ Note that all panics either abort the process or get caught by some call to `cat In particular, in std's [runtime service], the call to the user-provided `main` function is wrapped in `catch_unwind`. - [runtime service]: https://github.com/rust-lang/rust/blob/HEAD/library/std/src/rt.rs +[`library/core/src/panicking.rs`]: https://doc.rust-lang.org/core/panicking/index.html +[`compiler/rustc_hir/src/weak_lang_items.rs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_hir/src/weak_lang_items.rs +[`library/std/src/panicking.rs`]: https://github.com/rust-lang/rust/blob/HEAD/library/std/src/panicking.rs +[`compiler/rustc_passes/src/lang_items.rs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_passes/lang_items/index.html +[`extract_ast`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_passes/lang_items/fn.extract_ast.html diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 53a6c0cb5737d..81084132f0838 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -349,8 +349,8 @@ If you need to work with `#![no_std]` cross-compiling tests, consult the #### Conditional assembly tests based on instruction support Tests that depend on specific assembly instructions being available can use the -`//@ needs-asm-mnemonic: ` directive. This will skip the test if the -target backend does not support the specified instruction mnemonic. +`//@ needs-asm-mnemonic: ` directive. +This will skip the test if the target backend does not support the specified instruction mnemonic. For example, a test that requires the `RET` instruction: ```rust,ignore diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index caa400b573135..6c8e787ddbff7 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -183,8 +183,7 @@ The following directives will check rustc build settings and target settings: - `needs-threads` — ignores if the target does not have threading support - `needs-subprocess` — ignores if the target does not have subprocess support - `needs-symlink` — ignores if the target does not support symlinks. - This can be the case on Windows if the developer did not enable privileged symlink - permissions. + This can be the case on Windows if the developer did not enable privileged symlink permissions. - `ignore-std-debug-assertions` — ignores if std was built with debug assertions. - `needs-std-debug-assertions` — ignores if std was not built with debug assertions. - `ignore-std-remap-debuginfo` — ignores if std was built with remapping of it's sources. diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index d5f7d8b5fcb70..802df2286095d 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -15,30 +15,37 @@ the types have been filled in, which is possible after type checking has complet But it has some other interesting features that distinguish it from the HIR: - Like the MIR, the THIR only represents bodies, i.e. "executable code"; this includes - function bodies, but also `const` initializers, for example. Specifically, all [body owners] have - THIR created. Consequently, the THIR has no representation for items like `struct`s or `trait`s. + function bodies, but also `const` initializers, for example. + Specifically, all [body owners] have THIR created. + Consequently, the THIR has no representation for items like `struct`s or `trait`s. - Each body of THIR is only stored temporarily and is dropped as soon as it's no longer needed, as opposed to being stored until the end of the compilation process (which is what is done with the HIR). - Besides making the types of all nodes available, the THIR also has additional - desugaring compared to the HIR. For example, automatic references and dereferences + desugaring compared to the HIR. + For example, automatic references and dereferences are made explicit, and method calls and overloaded operators are converted into - plain function calls. Destruction scopes are also made explicit. + plain function calls. + Destruction scopes are also made explicit. -- Statements, expressions, and match arms are stored separately. For example, statements in the - `stmts` array reference expressions by their index (represented as a [`ExprId`]) in the `exprs` - array. +- Statements, expressions, match arms, blocks, and parameters are stored separately. + For example, + statements in the `stmts` array reference expressions by their index (represented as a + [`ExprId`]) in the `exprs` array. [HIR]: ./hir.md [`ExprId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/thir/struct.ExprId.html [body owners]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.BodyOwnerKind.html -The THIR lives in [`rustc_mir_build::thir`][thir-docs]. To construct a [`thir::Expr`], +The THIR lives in [`rustc_mir_build::thir`][thir-docs]. +To construct a [`thir::Expr`], you can use the [`thir_body`] function, passing in the memory arena where the THIR -will be allocated. Dropping this arena will result in the THIR being destroyed, -which is useful to keep peak memory in check. Having a THIR representation of +will be allocated. +Dropping this arena will result in the THIR being destroyed, +which is useful to keep peak memory in check. +Having a THIR representation of all bodies of a crate in memory at the same time would be very heavy. You can get a debug representation of the THIR by passing the `-Zunpretty=thir-tree` flag diff --git a/src/doc/rustc-dev-guide/src/tracing.md b/src/doc/rustc-dev-guide/src/tracing.md index 78a0fe4af2ff2..ae819003e1f3e 100644 --- a/src/doc/rustc-dev-guide/src/tracing.md +++ b/src/doc/rustc-dev-guide/src/tracing.md @@ -101,7 +101,7 @@ RUSTC_LOG=[typeck{key=.*name_of_item.*}] Different queries have different arguments. You can find a list of queries and their arguments in -[`rustc_middle/src/query/mod.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_middle/src/query/mod.rs#L18). +[`rustc_middle/src/queries.rs`](https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_middle/src/queries.rs). ## Broad module level filters diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 28021d3449437..b42f2f92c52bd 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -95,12 +95,13 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< // This covers the case where somebody does an import which should pull in an item, // but there's already an item with the same namespace and same name. Rust gives // priority to the not-imported one, so we should, too. - items.extend(doc.items.values().flat_map(|(item, renamed, import_ids)| { + items.extend(doc.items.values().flat_map(|entry| { // First, lower everything other than glob imports. + let item = entry.item; if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { return Vec::new(); } - let v = clean_maybe_renamed_item(cx, item, *renamed, import_ids); + let v = clean_maybe_renamed_item(cx, item, entry.renamed, &entry.import_ids); for item in &v { if let Some(name) = item.name && (cx.document_hidden() || !item.is_doc_hidden()) @@ -130,10 +131,11 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< _ => unreachable!(), } })); - items.extend(doc.items.values().flat_map(|(item, renamed, _)| { + items.extend(doc.items.values().flat_map(|entry| { // Now we actually lower the imports, skipping everything else. + let item = entry.item; if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted) + clean_use_statement(item, entry.renamed, path, hir::UseKind::Glob, cx, &mut inserted) } else { // skip everything else Vec::new() diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b2e38e491c704..05d4888c110cc 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -25,6 +25,7 @@ use rustc_resolve::rustdoc::{ DocFragment, add_doc_fragment, attrs_to_doc_fragments, inner_docs, span_of_fragments, }; use rustc_session::Session; +use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::{DUMMY_SP, FileName, Ident, Loc, RemapPathScopeComponents}; @@ -405,6 +406,23 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } impl Item { + pub(crate) fn cfg_parent_ids_for_detached_item(&self, tcx: TyCtxt<'_>) -> Vec { + let Some(def_id) = self.inline_stmt_id.or(self.item_id.as_local_def_id()) else { + return Vec::new(); + }; + let mut ids = Vec::new(); + let mut next = def_id; + while let Some(parent) = tcx.opt_local_parent(next) { + if parent == CRATE_DEF_ID { + break; + } + ids.push(parent); + next = parent; + } + ids.reverse(); + ids + } + /// Returns the effective stability of the item. /// /// This method should only be called after the `propagate-stability` pass has been run. diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 45061a02e7525..eb1dee2e16d7b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1492,7 +1492,7 @@ impl LinkCollector<'_, '_> { Some((sp, _)) => sp, None => item.attr_span(self.cx.tcx), }; - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( self.cx.tcx.sess, sym::intra_doc_pointers, span, diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 92798bb9bb011..1334595272f60 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -51,12 +51,31 @@ fn add_only_cfg_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) } } +/// This function goes through the attributes list (`new_attrs`) and extracts the attributes that +/// affect the cfg state propagated to detached items. +fn add_cfg_state_attributes(attrs: &mut Vec, new_attrs: &[Attribute]) { + for attr in new_attrs { + if let Attribute::Parsed(AttributeKind::Doc(d)) = attr + && (!d.cfg.is_empty() || !d.auto_cfg.is_empty() || !d.auto_cfg_change.is_empty()) + { + let mut new_attr = DocAttribute::default(); + new_attr.cfg = d.cfg.clone(); + new_attr.auto_cfg = d.auto_cfg.clone(); + new_attr.auto_cfg_change = d.auto_cfg_change.clone(); + attrs.push(Attribute::Parsed(AttributeKind::Doc(Box::new(new_attr)))); + } else if let Attribute::Parsed(AttributeKind::CfgTrace(..)) = attr { + // If it's a `cfg()` attribute, we keep it. + attrs.push(attr.clone()); + } + } +} + impl CfgPropagator<'_, '_> { // Some items need to merge their attributes with their parents' otherwise a few of them // (mostly `cfg` ones) will be missing. fn merge_with_parent_attributes(&mut self, item: &mut Item) { let mut attrs = Vec::new(); - // We only need to merge an item attributes with its parent's in case it's an impl as an + // We need to merge an item attributes with its parent's in case it's an impl as an // impl might not be defined in the same module as the item it implements. // // Otherwise, `cfg_info` already tracks everything we need so nothing else to do! @@ -69,6 +88,27 @@ impl CfgPropagator<'_, '_> { next_def_id = parent_def_id; } } + // We also need to merge an item attributes with its parent's in case it's a macro with + // the `#[macro_export]` attribute, because it might not be defined at crate root. + if matches!(item.kind, ItemKind::MacroItem(_)) + && item.inner.attrs.other_attrs.iter().any(|attr| { + matches!( + attr, + rustc_hir::Attribute::Parsed( + rustc_hir::attrs::AttributeKind::MacroExport { .. } + ) + ) + }) + { + for parent_def_id in &item.cfg_parent_ids_for_detached_item(self.cx.tcx) { + let mut parent_attrs = Vec::new(); + add_cfg_state_attributes( + &mut parent_attrs, + load_attrs(self.cx.tcx, parent_def_id.to_def_id()), + ); + merge_attrs(self.cx.tcx, &[], Some((&parent_attrs, None)), &mut self.cfg_info); + } + } let (_, cfg) = merge_attrs( self.cx.tcx, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 8746253d6ebba..5f119c23841e3 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -32,7 +32,7 @@ pub(crate) struct Module<'hir> { pub(crate) def_id: LocalDefId, pub(crate) renamed: Option, pub(crate) import_id: Option, - /// The key is the item `ItemId` and the value is: (item, renamed, Vec). + /// The key is the item `ItemId`. /// We use `FxIndexMap` to keep the insert order. /// /// `import_id` needs to be a `Vec` because we live in a dark world where you can have code @@ -52,10 +52,7 @@ pub(crate) struct Module<'hir> { /// So in this case, we don't want to have two items but just one with attributes from all /// non-glob imports to be merged. Glob imports attributes are always ignored, whether they're /// shadowed or not. - pub(crate) items: FxIndexMap< - (LocalDefId, Option), - (&'hir hir::Item<'hir>, Option, Vec), - >, + pub(crate) items: FxIndexMap<(LocalDefId, Option), ItemEntry<'hir>>, /// (def_id, renamed) -> (res, local_import_id) /// @@ -70,6 +67,13 @@ pub(crate) struct Module<'hir> { pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option, Option)>, } +#[derive(Debug)] +pub(crate) struct ItemEntry<'hir> { + pub(crate) item: &'hir hir::Item<'hir>, + pub(crate) renamed: Option, + pub(crate) import_ids: Vec, +} + impl Module<'_> { pub(crate) fn new( name: Symbol, @@ -172,9 +176,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { { let item = self.cx.tcx.hir_expect_item(local_def_id); let (ident, _, _) = item.expect_macro(); - top_level_module - .items - .insert((local_def_id, Some(ident.name)), (item, None, Vec::new())); + top_level_module.items.insert( + (local_def_id, Some(ident.name)), + ItemEntry { item, renamed: None, import_ids: Vec::new() }, + ); } } @@ -413,10 +418,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { .unwrap() .items .entry(key) - .and_modify(|v| v.2.push(import_id)) - .or_insert_with(|| (item, renamed, vec![import_id])); + .and_modify(|v| v.import_ids.push(import_id)) + .or_insert_with(|| ItemEntry { item, renamed, import_ids: vec![import_id] }); } else { - self.modules.last_mut().unwrap().items.insert(key, (item, renamed, Vec::new())); + self.modules + .last_mut() + .unwrap() + .items + .insert(key, ItemEntry { item, renamed, import_ids: Vec::new() }); } } } diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 52e602bbac577..8a12d1093b4b4 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -238,7 +238,7 @@ impl CollapsibleIf { }, [attr] - if matches!(Level::from_attr(attr), Some((Level::Expect, _))) + if matches!(Level::from_attr(attr.name(), || attr.id()), Some((Level::Expect, _))) && let Some(metas) = attr.meta_item_list() && let Some(MetaItemInner::MetaItem(meta_item)) = metas.first() && let [tool, lint_name] = meta_item.path.segments.as_slice() diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs index 619a70cd8dd10..b9bacc2b73a17 100644 --- a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs +++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs @@ -181,7 +181,7 @@ fn check_final_expr<'tcx>( match cx.tcx.hir_attrs(expr.hir_id) { [] => {}, [attr] => { - if matches!(Level::from_attr(attr), Some((Level::Expect, _))) + if matches!(Level::from_attr(attr.name(), || attr.id()), Some((Level::Expect, _))) && let metas = attr.meta_item_list() && let Some(lst) = metas && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice() diff --git a/tests/codegen-llvm/c-variadic-va-end.rs b/tests/codegen-llvm/c-variadic-va-end.rs new file mode 100644 index 0000000000000..b0d7371ba01c2 --- /dev/null +++ b/tests/codegen-llvm/c-variadic-va-end.rs @@ -0,0 +1,19 @@ +//@ add-minicore +//@ compile-flags: -Copt-level=3 +#![feature(c_variadic)] +#![crate_type = "lib"] + +unsafe extern "C" { + fn g(v: *mut u8); +} + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn f(mut args: ...) { + // CHECK: call void @llvm.va_start + unsafe { g(&raw mut args as *mut u8) } + // We expect one call to the LLVM va_end from our desugaring of `...`. The `Drop` implementation + // should only call the rust va_end intrinsic, which is a no-op. + // + // CHECK: call void @llvm.va_end + // CHECK-NOT: call void @llvm.va_end +} diff --git a/tests/codegen-llvm/double_panic_wasm.rs b/tests/codegen-llvm/double_panic_wasm.rs new file mode 100644 index 0000000000000..1eafe60503809 --- /dev/null +++ b/tests/codegen-llvm/double_panic_wasm.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -C panic=unwind -Copt-level=0 +//@ needs-unwind +//@ only-wasm32 + +#![crate_type = "lib"] + +// Test that `panic_in_cleanup` is called on webassembly targets when a panic +// occurs in a destructor during unwinding. + +extern "Rust" { + fn may_panic(); +} + +struct PanicOnDrop; + +impl Drop for PanicOnDrop { + fn drop(&mut self) { + unsafe { may_panic() } + } +} + +// CHECK-LABEL: @double_panic +// CHECK: invoke void @may_panic() +// CHECK: invoke void @{{.+}}drop_in_place{{.+}} +// CHECK: unwind label %[[TERMINATE:.*]] +// +// CHECK: [[TERMINATE]]: +// CHECK: call void @{{.*panic_in_cleanup}} +// CHECK: unreachable +#[no_mangle] +pub fn double_panic() { + let _guard = PanicOnDrop; + unsafe { may_panic() } +} diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs index a2ec19871d1fc..7c98ea94fdc13 100644 --- a/tests/codegen-llvm/terminating-catchpad.rs +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -9,6 +9,10 @@ // Ensure a catch-all generates: // - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) // - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) +// +// Unlike on windows, on Wasm, we specifically do want to catch foreign +// exceptions. To catch only C++ exceptions we'd need to call +// @llvm.wasm.get.exception and @llvm.wasm.get.ehselector in the catchpad. #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "lib"] @@ -36,8 +40,14 @@ fn panic_cannot_unwind() -> ! { #[no_mangle] #[rustc_nounwind] pub fn doesnt_unwind() { + // CHECK: catchswitch within none [label %{{.*}}] unwind to caller // emscripten: %catchpad = catchpad within %catchswitch [ptr null] // wasi: %catchpad = catchpad within %catchswitch [ptr null] // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] + // + // We don't call these intrinsics on wasm targets so we generate a catch_all + // instruction which also picks up foreign exceptions + // NOT: @llvm.wasm.get.exception + // NOT: @llvm.wasm.get.ehselector unwinds(); } diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index a5df237b7fddc..b516bb1508ec4 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -48,6 +48,12 @@ fn main() { includes: &["unix", "target_abi=\"eabihf\""], disallow: &["windows"], }); + // Regression test for #90834: Android must not have `target_env="gnu"`. + check(PrintCfg { + target: "i686-linux-android", + includes: &["unix", "target_os=\"android\""], + disallow: &["windows", "target_env=\"gnu\""], + }); } fn check(PrintCfg { target, includes, disallow }: PrintCfg) { diff --git a/tests/rustdoc-html/doc-cfg/decl-macro.rs b/tests/rustdoc-html/doc-cfg/decl-macro.rs new file mode 100644 index 0000000000000..e97da8647a6ab --- /dev/null +++ b/tests/rustdoc-html/doc-cfg/decl-macro.rs @@ -0,0 +1,68 @@ +// Regression test for +//@ compile-flags: --cfg feature="routing" + +#![crate_name = "foo"] +#![feature(doc_cfg)] + +#[cfg(feature = "routing")] +pub mod routing { + //@ has 'foo/macro.vpath.html' '//*[@class="stab portability"]' 'Available on crate feature routing only.' + #[macro_export] + macro_rules! vpath { + () => {}; + } +} + +#[doc(cfg(feature = "manual"))] +pub mod manual { + //@ has 'foo/macro.manual_macro.html' '//*[@class="stab portability"]' 'Available on crate feature manual only.' + #[macro_export] + macro_rules! manual_macro { + () => {}; + } +} + +#[doc(cfg(feature = "outer"))] +pub mod outer { + #[cfg(feature = "routing")] + pub mod inner { + //@ has 'foo/macro.nested_macro.html' '//*[@class="stab portability"]' 'Available on crate features outer and routing only.' + #[macro_export] + macro_rules! nested_macro { + () => {}; + } + } +} + +#[cfg(feature = "routing")] +#[doc(auto_cfg = false)] +pub mod auto_cfg_disabled { + //@ count 'foo/macro.no_auto_cfg_macro.html' '//*[@class="stab portability"]' 0 + #[macro_export] + macro_rules! no_auto_cfg_macro { + () => {}; + } +} + +#[cfg(feature = "routing")] +#[doc(auto_cfg(hide(feature = "routing")))] +pub mod auto_cfg_hidden { + //@ count 'foo/macro.hidden_cfg_macro.html' '//*[@class="stab portability"]' 0 + #[macro_export] + macro_rules! hidden_cfg_macro { + () => {}; + } +} + +#[cfg(feature = "routing")] +#[doc(auto_cfg(hide(feature = "routing")))] +pub mod auto_cfg_shown { + #[doc(auto_cfg(show(feature = "routing")))] + pub mod inner { + //@ has 'foo/macro.shown_cfg_macro.html' '//*[@class="stab portability"]' 'Available on crate feature routing only.' + #[macro_export] + macro_rules! shown_cfg_macro { + () => {}; + } + } +} diff --git a/tests/ui/issues/issue-31769.rs b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs similarity index 70% rename from tests/ui/issues/issue-31769.rs rename to tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs index 354c1be9ed554..f295ecf302598 100644 --- a/tests/ui/issues/issue-31769.rs +++ b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs @@ -1,3 +1,4 @@ +//! Regression test for fn main() { #[inline] struct Foo; //~ ERROR attribute cannot be used on #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to a struct, enum, or union diff --git a/tests/ui/issues/issue-31769.stderr b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr similarity index 77% rename from tests/ui/issues/issue-31769.stderr rename to tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr index 0f75e84f2a704..fc8e22f171c20 100644 --- a/tests/ui/issues/issue-31769.stderr +++ b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr @@ -1,5 +1,5 @@ error: `#[inline]` attribute cannot be used on structs - --> $DIR/issue-31769.rs:2:5 + --> $DIR/dont-allow-inline-and-repr-at-invalid-positions.rs:3:5 | LL | #[inline] struct Foo; | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[inline] struct Foo; = help: `#[inline]` can only be applied to functions error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-31769.rs:3:12 + --> $DIR/dont-allow-inline-and-repr-at-invalid-positions.rs:4:12 | LL | #[repr(C)] fn foo() {} | ^ ----------- not a struct, enum, or union diff --git a/tests/ui/issues/issue-33202.rs b/tests/ui/attributes/repr-on-single-variant-Enum.rs similarity index 67% rename from tests/ui/issues/issue-33202.rs rename to tests/ui/attributes/repr-on-single-variant-Enum.rs index 3fef98606afab..ab45c76ef5aae 100644 --- a/tests/ui/issues/issue-33202.rs +++ b/tests/ui/attributes/repr-on-single-variant-Enum.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #[repr(C)] pub enum CPOption { diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr new file mode 100644 index 0000000000000..fd9d7777a3886 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr @@ -0,0 +1,14 @@ +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:26:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:30:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs new file mode 100644 index 0000000000000..98b5f063d5844 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs @@ -0,0 +1,45 @@ +//@ add-minicore +//@ ignore-backends: gcc +// +//@ revisions: riscv32e sparc avr m68k msp430 +// +//@[riscv32e] compile-flags: --target riscv32e-unknown-none-elf +//@[riscv32e] needs-llvm-components: riscv +// +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +// +//@[avr] compile-flags: --target avr-none -Ctarget-cpu=atmega328p +//@[avr] needs-llvm-components: avr +// +//@[m68k] compile-flags: --target m68k-unknown-none-elf -Ctarget-cpu=M68020 +//@[m68k] needs-llvm-components: m68k +// +//@[msp430] compile-flags: --target msp430-none-elf -Ctarget-cpu=msp430 +//@[msp430] needs-llvm-components: msp430 +#![feature(no_core, lang_items, rustc_attrs, c_variadic)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(transparent)] +struct VaListInner { + ptr: *const c_void, +} + +#[repr(transparent)] +#[lang = "va_list"] +pub struct VaList<'a> { + inner: VaListInner, + _marker: PhantomData<&'a mut ()>, +} + +pub unsafe extern "C" fn test(_: i32, ap: ...) {} +//~^ ERROR C-variadic function definitions on this target are unstable + +trait Trait { + unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + //~^ ERROR C-variadic function definitions on this target are unstable +} diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-view-types.rs b/tests/ui/feature-gates/feature-gate-view-types.rs new file mode 100644 index 0000000000000..eb0c26d61db4a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-view-types.rs @@ -0,0 +1,17 @@ +struct Foo { + a: usize, + b: usize, +} + +fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + //~^ ERROR view types are experimental + //~| ERROR view types are experimental + a.a += 1; + b.b += 1; +} + +fn main() { + let mut foo = Foo { a: 0, b: 0 }; + bar(&mut foo, &mut foo); + //~^ ERROR cannot borrow `foo` as mutable more than once at a time +} diff --git a/tests/ui/feature-gates/feature-gate-view-types.stderr b/tests/ui/feature-gates/feature-gate-view-types.stderr new file mode 100644 index 0000000000000..661783ec59202 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-view-types.stderr @@ -0,0 +1,33 @@ +error[E0658]: view types are experimental + --> $DIR/feature-gate-view-types.rs:6:19 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: view types are experimental + --> $DIR/feature-gate-view-types.rs:6:38 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^^^^^^ + | + = note: see issue #155938 for more information + = help: add `#![feature(view_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/feature-gate-view-types.rs:15:19 + | +LL | bar(&mut foo, &mut foo); + | --- -------- ^^^^^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0499, E0658. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/issues/issue-38763.rs b/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs similarity index 72% rename from tests/ui/issues/issue-38763.rs rename to tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs index 87c758db1723c..4bd78a423cd2c 100644 --- a/tests/ui/issues/issue-38763.rs +++ b/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass //@ needs-threads diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index 0ebcf8e58d627..cb3836305c1ab 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -14,7 +14,9 @@ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:36:22 | LL | use crate::b::a::foo::S; - | ^^^ private module import + | ^^^ - struct `S` is not publicly re-exported + | | + | private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:24:17 @@ -31,7 +33,9 @@ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:37:22 | LL | use crate::b::b::foo::S as T; - | ^^^ private module import + | ^^^ - struct `S` is not publicly re-exported + | | + | private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:29:17 diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr new file mode 100644 index 0000000000000..815f91a0b6c8a --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:36:16 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:46:20 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr new file mode 100644 index 0000000000000..0295cb29ca3e2 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:39:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:49:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr new file mode 100644 index 0000000000000..0295cb29ca3e2 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:39:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:49:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr new file mode 100644 index 0000000000000..0295cb29ca3e2 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:39:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:49:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.rs b/tests/ui/imports/suggest-public-reexport-for-use.rs new file mode 100644 index 0000000000000..1658735e36cf9 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.rs @@ -0,0 +1,62 @@ +//@ revisions: edition2015 edition2018 edition2021 edition2024 +//@ [edition2015] edition:2015 +//@ [edition2018] edition:2018 +//@ [edition2021] edition:2021 +//@ [edition2024] edition:2024 + +// When a `use` statement accesses an item through a private module, +// the compiler should suggest a public re-export if one exists. + +mod outer { + pub use self::inner::MyStruct; + pub use self::inner::my_function; + pub use self::inner::MyTrait; + pub use self::inner::MyEnum; + + mod inner { + pub struct MyStruct; + pub fn my_function() {} + pub trait MyTrait {} + pub enum MyEnum { + Variant, + } + } +} + +// Accessing items through a private module should suggest the public re-export. +use outer::inner::MyStruct; //~ ERROR module `inner` is private +use outer::inner::my_function; //~ ERROR module `inner` is private +use outer::inner::MyTrait; //~ ERROR module `inner` is private +use outer::inner::MyEnum; //~ ERROR module `inner` is private + +// From a sibling module, the suggestion should keep the full path +// (shortening to `super::` would not reduce the segment count here). +mod sibling { + #[cfg(edition2015)] + use outer::inner::MyStruct; //[edition2015]~ ERROR module `inner` is private + + #[cfg(not(edition2015))] + use crate::outer::inner::MyStruct; //[edition2018,edition2021,edition2024]~ ERROR module `inner` is private +} + +// From a deeply nested module, the suggestion should keep the full path. +mod deep { + mod nested { + #[cfg(edition2015)] + use outer::inner::MyStruct; //[edition2015]~ ERROR module `inner` is private + + #[cfg(not(edition2015))] + use crate::outer::inner::MyStruct; //[edition2018,edition2021,edition2024]~ ERROR module `inner` is private + } +} + +// Items with no public re-export should say "not publicly re-exported". +mod no_reexport { + mod hidden { + pub struct Secret; + } +} + +use no_reexport::hidden::Secret; //~ ERROR module `hidden` is private + +fn main() {} diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr index f62ef3ae2e4cc..5d1e003c703b4 100644 --- a/tests/ui/privacy/privacy1.stderr +++ b/tests/ui/privacy/privacy1.stderr @@ -4,6 +4,12 @@ error[E0603]: module `baz` is private LL | use bar::baz::{foo, bar}; | ^^^ private module | +help: consider importing this function through its public re-export instead: + bar::foo + --> $DIR/privacy1.rs:139:24 + | +LL | use bar::baz::{foo, bar}; + | ^^^ note: the module `baz` is defined here --> $DIR/privacy1.rs:57:5 | @@ -16,12 +22,17 @@ error[E0603]: module `baz` is private LL | use bar::baz::{foo, bar}; | ^^^ private module | +help: consider importing this function through its public re-export instead: + bar::bar + --> $DIR/privacy1.rs:139:29 + | +LL | use bar::baz::{foo, bar}; + | ^^^ note: the module `baz` is defined here --> $DIR/privacy1.rs:57:5 | LL | mod baz { | ^^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0603]: module `baz` is private --> $DIR/privacy1.rs:148:18 @@ -39,7 +50,9 @@ error[E0603]: module `i` is private --> $DIR/privacy1.rs:172:20 | LL | use self::foo::i::A; - | ^ private module + | ^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `i` is defined here --> $DIR/privacy1.rs:177:9 diff --git a/tests/ui/issues/issue-19001.rs b/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs similarity index 73% rename from tests/ui/issues/issue-19001.rs rename to tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs index 51aebf88c95fb..97fa08fab1d93 100644 --- a/tests/ui/issues/issue-19001.rs +++ b/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #![allow(dead_code)] // check that we handle recursive arrays correctly in `type_of` diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index 8827d1bbb49d3..21f80198f1978 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -10,9 +10,14 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -24,9 +29,14 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -37,6 +47,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 8ff9771b9ade6..54a53a097bcbe 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -10,13 +10,18 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const K: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -28,13 +33,18 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const I: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -45,6 +55,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const _: u32 = T::C; diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs index c9a64de7f6bba..9616144ec3103 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs @@ -11,6 +11,7 @@ fn outer() { // outer function const K: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here } @@ -18,6 +19,7 @@ impl Tr for T { // outer impl block const C: u32 = { const I: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here I }; @@ -26,6 +28,7 @@ impl Tr for T { // outer impl block struct S(U32<{ // outer struct const _: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here 0 }>); diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed new file mode 100644 index 0000000000000..fea9f7a6f8516 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + let size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + let K: u32 = A::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs new file mode 100644 index 0000000000000..3f87f3e2a2ae8 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + const size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + const K: u32 = Self::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr new file mode 100644 index 0000000000000..3d3280cfbbb4b --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr @@ -0,0 +1,46 @@ +error[E0401]: can't use generic parameters from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:11:46 + | +LL | const fn size_plus_one() -> usize { + | - type parameter from outer item +LL | +LL | const size: usize = core::mem::size_of::(); + | ---- ^ use of generic parameter from outer item + | | + | generic parameter used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const size: usize = core::mem::size_of::(); +LL + let size: usize = core::mem::size_of::(); + | + +error[E0401]: can't use `Self` from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:28:24 + | +LL | impl A { + | ---- `Self` type implicitly declared here, by this `impl` +... +LL | const K: u32 = Self::VALUE; + | - ^^^^ use of `Self` from outer item + | | + | `Self` used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: refer to the type directly here instead + | +LL - const K: u32 = Self::VALUE; +LL + const K: u32 = A::VALUE; + | +help: try using a local `let` binding instead + | +LL - const K: u32 = Self::VALUE; +LL + let K: u32 = Self::VALUE; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr index b062341dc8be8..bbec8380fd032 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.stderr +++ b/tests/ui/shadowed/shadowed-use-visibility.stderr @@ -14,6 +14,11 @@ note: ...and refers to the module `foo` which is defined here | LL | mod foo { | ^^^^^^^ +help: consider importing this function instead + | +LL - use crate::foo::bar::f as g; +LL + use foo::f as g; + | error[E0603]: module import `f` is private --> $DIR/shadowed-use-visibility.rs:15:10 @@ -31,6 +36,11 @@ note: ...and refers to the module `foo` which is defined here | LL | mod foo { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use bar::f::f; +LL + use bar::f; + | error: aborting due to 2 previous errors diff --git a/tests/ui/use/use-mod/use-mod-3.stderr b/tests/ui/use/use-mod/use-mod-3.stderr index 049b50e5b3b0f..17e5b4219de23 100644 --- a/tests/ui/use/use-mod/use-mod-3.stderr +++ b/tests/ui/use/use-mod/use-mod-3.stderr @@ -17,6 +17,8 @@ error[E0603]: module `bar` is private | LL | use foo::bar::{ | ^^^ private module +LL | Bar + | --- type alias `Bar` is not publicly re-exported | note: the module `bar` is defined here --> $DIR/use-mod-3.rs:9:5