Merge pull request #4820 from rust-lang/rustup-2026-01-20

Automatic Rustup
This commit is contained in:
Ralf Jung 2026-01-20 08:02:03 +00:00 committed by GitHub
commit 0aac6d1367
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
709 changed files with 7887 additions and 3806 deletions

View file

@ -2,6 +2,7 @@
name: Internal Compiler Error
about: Create a report for an internal compiler error in rustc.
labels: C-bug, I-ICE, T-compiler
title: "[ICE]: "
---
<!--
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide

View file

@ -305,30 +305,22 @@ jobs:
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv
# This job isused to tell bors the final status of the build, as there is no practical way to detect
# when a workflow is successful listening to webhooks only in our current bors implementation (homu).
# This job is used to publish toolstate for successful auto builds.
outcome:
name: bors build finished
name: publish toolstate
runs-on: ubuntu-24.04
needs: [ calculate_matrix, job ]
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }}
environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }}
steps:
- name: checkout the source code
uses: actions/checkout@v5
with:
fetch-depth: 2
# Calculate the exit status of the whole CI workflow.
# If all dependent jobs were successful, this exits with 0 (and the outcome job continues successfully).
# If a some dependent job has failed, this exits with 1.
- name: calculate the correct exit status
run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
# Publish the toolstate if an auto build succeeds (just before push to the default branch)
- name: publish toolstate
run: src/ci/publish_toolstate.sh
shell: bash
if: needs.calculate_matrix.outputs.run_type == 'auto'
env:
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
TOOLSTATE_PUBLISH: 1

View file

@ -62,19 +62,9 @@ jobs:
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
rustup default $TOOLCHAIN
- name: cargo update compiler & tools
# Remove first line that always just says "Updating crates.io index"
run: |
echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update library
run: |
echo -e "\nlibrary dependencies:" >> cargo_update.log
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update rustbook
run: |
echo -e "\nrustbook dependencies:" >> cargo_update.log
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update
run: ./src/tools/update-lockfile.sh
- name: upload Cargo.lock artifact for use in PR
uses: actions/upload-artifact@v4
with:

View file

@ -3767,6 +3767,7 @@ dependencies = [
name = "rustc_driver_impl"
version = "0.0.0"
dependencies = [
"anstyle",
"ctrlc",
"jiff",
"libc",
@ -3792,6 +3793,7 @@ dependencies = [
"rustc_index",
"rustc_infer",
"rustc_interface",
"rustc_lexer",
"rustc_lint",
"rustc_log",
"rustc_macros",
@ -3887,11 +3889,13 @@ dependencies = [
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
"rustc_parse",
"rustc_proc_macro",
"rustc_serialize",
"rustc_session",
"rustc_span",
"scoped-tls",
"smallvec",
"thin-vec",
"tracing",

View file

@ -1,6 +1,7 @@
use std::assert_matches::assert_matches;
use std::str::FromStr;
use rustc_data_structures::assert_matches;
use super::*;
#[allow(non_snake_case)]

View file

@ -3348,7 +3348,8 @@ impl UseTree {
/// Distinguishes between `Attribute`s that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
pub enum AttrStyle {
Outer,
Inner,

View file

@ -40,13 +40,13 @@ impl DocFragmentKind {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum CommentKind {
Line,
Block,
}
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum InvisibleOrigin {
// From the expansion of a metavariable in a declarative macro.
MetaVar(MetaVarKind),
@ -123,7 +123,7 @@ impl fmt::Display for MetaVarKind {
/// Describes how a sequence of token trees is delimited.
/// Cannot use `proc_macro::Delimiter` directly because this
/// structure should implement some additional traits.
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum Delimiter {
/// `( ... )`
Parenthesis,
@ -186,7 +186,7 @@ impl Delimiter {
// type. This means that float literals like `1f32` are classified by this type
// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
// given the `Float` kind.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum LitKind {
Bool, // AST only, must never appear in a `Token`
Byte,
@ -203,7 +203,7 @@ pub enum LitKind {
}
/// A literal token.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Lit {
pub kind: LitKind,
pub symbol: Symbol,
@ -349,7 +349,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
.contains(&name)
}
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)]
pub enum IdentIsRaw {
No,
Yes,
@ -376,7 +376,7 @@ impl From<bool> for IdentIsRaw {
}
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum TokenKind {
/* Expression-operator symbols. */
/// `=`
@ -526,7 +526,7 @@ pub enum TokenKind {
Eof,
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
@ -625,12 +625,12 @@ impl TokenKind {
}
impl Token {
pub fn new(kind: TokenKind, span: Span) -> Self {
pub const fn new(kind: TokenKind, span: Span) -> Self {
Token { kind, span }
}
/// Some token that will be thrown away later.
pub fn dummy() -> Self {
pub const fn dummy() -> Self {
Token::new(TokenKind::Question, DUMMY_SP)
}

View file

@ -5,6 +5,7 @@
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
use std::borrow::Cow;
use std::hash::Hash;
use std::ops::Range;
use std::sync::Arc;
use std::{cmp, fmt, iter, mem};
@ -22,7 +23,7 @@ use crate::token::{self, Delimiter, Token, TokenKind};
use crate::{AttrVec, Attribute};
/// Part of a `TokenStream`.
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum TokenTree {
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
/// delimiters are implicitly represented by `Delimited`.
@ -538,7 +539,7 @@ pub struct AttrsTarget {
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
/// part of `proc_macro::Spacing`) comes in useful.
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum Spacing {
/// The token cannot join with the following token to form a compound
/// token.
@ -595,7 +596,7 @@ pub enum Spacing {
}
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
#[derive(Clone, Debug, Default, Encodable, Decodable)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
impl TokenStream {
@ -811,14 +812,6 @@ impl TokenStream {
}
}
impl PartialEq<TokenStream> for TokenStream {
fn eq(&self, other: &TokenStream) -> bool {
self.iter().eq(other.iter())
}
}
impl Eq for TokenStream {}
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
@ -970,7 +963,8 @@ impl TokenCursor {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
pub struct DelimSpan {
pub open: Span,
pub close: Span,
@ -994,7 +988,7 @@ impl DelimSpan {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub struct DelimSpacing {
pub open: Spacing,
pub close: Spacing,

View file

@ -51,7 +51,7 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::lints::DelayedLint;
use rustc_hir::lints::{AttributeLint, DelayedLint};
use rustc_hir::{
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@ -1022,12 +1022,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.attribute_parser.parse_attribute_list(
attrs,
target_span,
target_hir_id,
target,
OmitDoc::Lower,
|s| l.lower(s),
|l| {
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|lint_id, span, kind| {
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
lint_id,
id: target_hir_id,
span,
kind,
}));
},
)
}
@ -2380,7 +2384,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Some(ConstItemRhs::TypeConst(anon)) => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
None if attr::contains_name(attrs, sym::type_const) => {
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(

View file

@ -29,7 +29,6 @@ pub(crate) fn extern_abi_enabled(
})
}
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
match extern_abi_enabled(features, span, abi) {
Ok(_) => (),

View file

@ -13,15 +13,11 @@ use crate::errors;
macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
}
}};
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
}
}};
@ -31,13 +27,11 @@ macro_rules! gate {
macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, $name, $span, $explain).emit();
}
}};
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
for note in $notes {
diag.note(*note);
@ -491,7 +485,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
{
#[allow(rustc::untranslatable_diagnostic)]
// Emit yield_expr as the error, since that will be sufficient. You can think of it
// as coroutines and gen_blocks imply yield_expr.
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
@ -523,7 +516,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if !visitor.features.min_generic_const_args()
&& !span.allows_unstable(sym::min_generic_const_args)
{
#[allow(rustc::untranslatable_diagnostic)]
feature_err(
&visitor.sess,
sym::min_generic_const_args,
@ -559,7 +551,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!"
{
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
.emit();
} else {

View file

@ -230,7 +230,7 @@ attr_parsing_unstable_cfg_target_compact =
compact `cfg(target(..))` is experimental and subject to change
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
.help = if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`

View file

@ -9,7 +9,7 @@ use rustc_feature::{
};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion};
use rustc_hir::{AttrPath, RustcVersion, Target};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{exp, parse_in};
use rustc_session::Session;
@ -373,6 +373,7 @@ fn parse_cfg_attr_internal<'a>(
ParsedDescription::Attribute,
pred_span,
CRATE_NODE_ID,
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
&meta,
@ -411,7 +412,6 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {

View file

@ -2,8 +2,8 @@ use rustc_ast::token::Token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrStyle, NodeId, token};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::AttrPath;
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::Parser;
use rustc_session::Session;
@ -91,6 +91,8 @@ pub fn parse_cfg_select(
ParsedDescription::Macro,
cfg_span,
lint_node_id,
// Doesn't matter what the target actually is here.
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
&meta,

View file

@ -136,6 +136,15 @@ impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
}
pub(crate) struct NoMainParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
const PATH: &[Symbol] = &[sym::no_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
}
pub(crate) struct RustcCoherenceIsCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {

View file

@ -0,0 +1,31 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::{Symbol, sym};
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
pub(crate) struct DoNotRecommendParser;
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let attr_span = cx.attr_span;
if !matches!(args, ArgParser::NoArgs) {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
attr_span,
);
}
Some(AttributeKind::DoNotRecommend { attr_span })
}
}

View file

@ -50,7 +50,7 @@ fn check_attr_not_crate_level<S: Stage>(
span: Span,
attr_name: Symbol,
) -> bool {
if cx.shared.target.is_some_and(|target| target == Target::Crate) {
if cx.shared.target == Target::Crate {
cx.emit_err(DocAttrNotCrateLevel { span, attr_name });
return false;
}
@ -59,7 +59,7 @@ fn check_attr_not_crate_level<S: Stage>(
/// Checks that an attribute is used at the crate level. Returns `true` if valid.
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
if cx.shared.target.is_some_and(|target| target != Target::Crate) {
if cx.shared.target != Target::Crate {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::AttrCrateLevelOnly,

View file

@ -141,8 +141,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
macro report_unstable_modifier($feature: ident) {
if !features.$feature() {
// FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)]
feature_err(
sess,
sym::$feature,
@ -658,3 +656,12 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
Some(AttributeKind::Linkage(linkage, cx.attr_span))
}
}
pub(crate) struct NeedsAllocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
const PATH: &[Symbol] = &[sym::needs_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
}

View file

@ -39,6 +39,7 @@ pub(crate) mod confusables;
pub(crate) mod crate_level;
pub(crate) mod debugger;
pub(crate) mod deprecation;
pub(crate) mod do_not_recommend;
pub(crate) mod doc;
pub(crate) mod dummy;
pub(crate) mod inline;
@ -57,6 +58,7 @@ pub(crate) mod pin_v2;
pub(crate) mod proc_macro_attrs;
pub(crate) mod prototype;
pub(crate) mod repr;
pub(crate) mod rustc_allocator;
pub(crate) mod rustc_dump;
pub(crate) mod rustc_internal;
pub(crate) mod semantics;

View file

@ -0,0 +1,60 @@
use super::prelude::*;
pub(crate) struct RustcAllocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
const PATH: &[Symbol] = &[sym::rustc_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
}
pub(crate) struct RustcAllocatorZeroedParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
}
pub(crate) struct RustcAllocatorZeroedVariantParser;
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::RustcAllocatorZeroedVariant { name })
}
}
pub(crate) struct RustcDeallocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_deallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
}
pub(crate) struct RustcReallocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_reallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
}

View file

@ -164,21 +164,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
}
}
pub(crate) struct RustcLintDiagnosticsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintDiagnosticsParser {
const PATH: &[Symbol] = &[sym::rustc_lint_diagnostics];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: false })),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintDiagnostics;
}
pub(crate) struct RustcLintOptDenyFieldAccessParser;
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
@ -320,3 +305,27 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParse
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
}
pub(crate) struct RustcNounwindParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
const PATH: &[Symbol] = &[sym::rustc_nounwind];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::ForeignFn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
}
pub(crate) struct RustcOffloadKernelParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
}

View file

@ -4,9 +4,6 @@ use super::prelude::*;
pub(crate) struct TransparencyParser;
// FIXME(jdonszelmann): make these proper diagnostics
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;

View file

@ -8,7 +8,7 @@ use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, HirId};
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
@ -28,19 +28,20 @@ use crate::attributes::codegen_attrs::{
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
WindowsSubsystemParser,
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoMainParser, NoStdParser,
PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser,
TypeLengthLimitParser, WindowsSubsystemParser,
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::do_not_recommend::DoNotRecommendParser;
use crate::attributes::doc::DocParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::instruction_set::InstructionSetParser;
use crate::attributes::link_attrs::{
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser, StdInternalSymbolParser,
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
@ -63,6 +64,10 @@ use crate::attributes::proc_macro_attrs::{
};
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_allocator::{
RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser,
RustcDeallocatorParser, RustcReallocatorParser,
};
use crate::attributes::rustc_dump::{
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
RustcDumpVtable,
@ -70,10 +75,10 @@ use crate::attributes::rustc_dump::{
use crate::attributes::rustc_internal::{
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser,
RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser,
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
@ -201,6 +206,7 @@ attribute_parsers!(
Single<CrateNameParser>,
Single<CustomMirParser>,
Single<DeprecationParser>,
Single<DoNotRecommendParser>,
Single<DummyParser>,
Single<ExportNameParser>,
Single<IgnoreParser>,
@ -221,6 +227,7 @@ attribute_parsers!(
Single<PatternComplexityLimitParser>,
Single<ProcMacroDeriveParser>,
Single<RecursionLimitParser>,
Single<RustcAllocatorZeroedVariantParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@ -257,9 +264,11 @@ attribute_parsers!(
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NeedsAllocatorParser>>,
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoLinkParser>>,
Single<WithoutArgs<NoMainParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
@ -270,21 +279,26 @@ attribute_parsers!(
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<RustcAllocatorParser>>,
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcDeallocatorParser>>,
Single<WithoutArgs<RustcDumpDefParents>>,
Single<WithoutArgs<RustcDumpItemBounds>>,
Single<WithoutArgs<RustcDumpPredicates>>,
Single<WithoutArgs<RustcDumpUserArgs>>,
Single<WithoutArgs<RustcDumpVtable>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
Single<WithoutArgs<RustcMainParser>>,
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
Single<WithoutArgs<RustcNounwindParser>>,
Single<WithoutArgs<RustcOffloadKernelParser>>,
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
Single<WithoutArgs<RustcReallocatorParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
@ -417,8 +431,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
) {
return;
}
let id = self.target_id;
(self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind });
(self.emit_lint)(LintId::of(lint), span, kind);
}
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
@ -663,11 +676,11 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
/// The span of the syntactical component this attribute was applied to
pub(crate) target_span: Span,
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
pub(crate) target_id: S::Id,
pub(crate) target: Option<rustc_hir::Target>,
pub(crate) target: rustc_hir::Target,
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
}
/// Context given to every attribute parser during finalization.

View file

@ -6,10 +6,10 @@ use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
use rustc_errors::DiagCtxtHandle;
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLint;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::{BuiltinLintDiag, LintId};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
@ -113,16 +113,15 @@ impl<'sess> AttributeParser<'sess, Early> {
p.parse_attribute_list(
attrs,
target_span,
target_node_id,
target,
OmitDoc::Skip,
std::convert::identity,
|lint| {
|lint_id, span, kind| {
sess.psess.buffer_lint(
lint.lint_id.lint,
lint.span,
lint.id,
BuiltinLintDiag::AttributeLint(lint.kind),
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
},
)
@ -135,6 +134,7 @@ impl<'sess> AttributeParser<'sess, Early> {
attr: &ast::Attribute,
target_span: Span,
target_node_id: NodeId,
target: Target,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
@ -163,6 +163,7 @@ impl<'sess> AttributeParser<'sess, Early> {
ParsedDescription::Attribute,
target_span,
target_node_id,
target,
features,
emit_errors,
&args,
@ -183,6 +184,7 @@ impl<'sess> AttributeParser<'sess, Early> {
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
target: Target,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
args: &I,
@ -196,29 +198,22 @@ impl<'sess> AttributeParser<'sess, Early> {
sess,
stage: Early { emit_errors },
};
let mut emit_lint = |lint: AttributeLint<NodeId>| {
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
sess.psess.buffer_lint(
lint.lint_id.lint,
lint.span,
lint.id,
BuiltinLintDiag::AttributeLint(lint.kind),
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
&mut emit_lint,
target_node_id,
)
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
}
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
shared: SharedContext {
cx: &mut parser,
target_span,
target_id: target_node_id,
target: None,
target,
emit_lint: &mut emit_lint,
},
attr_span,
@ -266,11 +261,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
&mut self,
attrs: &[ast::Attribute],
target_span: Span,
target_id: S::Id,
target: Target,
omit_doc: OmitDoc,
lower_span: impl Copy + Fn(Span) -> Span,
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
) -> Vec<Attribute> {
let mut attributes = Vec::new();
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
@ -326,7 +320,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
target_id,
);
let parts =
@ -378,8 +371,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
shared: SharedContext {
cx: self,
target_span,
target_id,
target: Some(target),
target,
emit_lint: &mut emit_lint,
},
attr_span,
@ -427,13 +419,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
for f in &S::parsers().finalizers {
if let Some(attr) = f(&mut FinalizeContext {
shared: SharedContext {
cx: self,
target_span,
target_id,
target: Some(target),
emit_lint: &mut emit_lint,
},
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
all_attrs: &attr_paths,
}) {
attributes.push(Attribute::Parsed(attr));

View file

@ -113,8 +113,12 @@ impl ArgParser {
Some(match value {
AttrArgs::Empty => Self::NoArgs,
AttrArgs::Delimited(args) => {
// The arguments of rustc_dummy are not validated if the arguments are delimited
if parts == &[sym::rustc_dummy] {
// The arguments of rustc_dummy and diagnostic::do_not_recommend are not validated
// if the arguments are delimited.
// See https://doc.rust-lang.org/reference/attributes/diagnostics.html#r-attributes.diagnostic.namespace.unknown-invalid-syntax
if parts == &[sym::rustc_dummy]
|| parts == &[sym::diagnostic, sym::do_not_recommend]
{
return Some(ArgParser::List(MetaItemListParser {
sub_parsers: ThinVec::new(),
span: args.dspan.entire(),

View file

@ -1,7 +1,7 @@
use rustc_ast::Safety;
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir::AttrPath;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::LintId;
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
use rustc_span::Span;
@ -15,8 +15,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attr_path: &AttrPath,
attr_span: Span,
attr_safety: Safety,
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
target_id: S::Id,
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
return;
@ -82,16 +81,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
},
);
} else {
emit_lint(AttributeLint {
lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
id: target_id,
span: path_span,
kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
emit_lint(
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
path_span,
AttributeLintKind::UnsafeAttrOutsideUnsafe {
attribute_name_span: path_span,
sugg_spans: not_from_proc_macro
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
},
})
)
}
}

View file

@ -253,19 +253,52 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
}
let region = region.as_var();
let borrow = BorrowData {
let borrow = |activation_location| BorrowData {
kind,
region,
reserve_location: location,
activation_location: TwoPhaseActivation::NotTwoPhase,
activation_location,
borrowed_place,
assigned_place: *assigned_place,
};
let (idx, _) = self.location_map.insert_full(location, borrow);
let idx = BorrowIndex::from(idx);
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
let idx = if !kind.is_two_phase_borrow() {
debug!(" -> {:?}", location);
let (idx, _) = self
.location_map
.insert_full(location, borrow(TwoPhaseActivation::NotTwoPhase));
BorrowIndex::from(idx)
} else {
// When we encounter a 2-phase borrow statement, it will always
// be assigning into a temporary TEMP:
//
// TEMP = &foo
//
// so extract `temp`.
let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
assigned_place,
);
};
// Consider the borrow not activated to start. When we find an activation, we'll update
// this field.
let (idx, _) = self
.location_map
.insert_full(location, borrow(TwoPhaseActivation::NotActivated));
let idx = BorrowIndex::from(idx);
// Insert `temp` into the list of pending activations. From
// now on, we'll be on the lookout for a use of it. Note that
// we are guaranteed that this use will come after the
// assignment.
let prev = self.pending_activations.insert(temp, idx);
assert_eq!(prev, None, "temporary associated with multiple two phase borrows");
idx
};
self.local_map.entry(borrowed_place.local).or_default().insert(idx);
}
@ -334,62 +367,3 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
self.super_rvalue(rvalue, location)
}
}
impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
/// If this is a two-phase borrow, then we will record it
/// as "pending" until we find the activating use.
fn insert_as_pending_if_two_phase(
&mut self,
start_location: Location,
assigned_place: &mir::Place<'tcx>,
kind: mir::BorrowKind,
borrow_index: BorrowIndex,
) {
debug!(
"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
start_location, assigned_place, borrow_index,
);
if !kind.allows_two_phase_borrow() {
debug!(" -> {:?}", start_location);
return;
}
// When we encounter a 2-phase borrow statement, it will always
// be assigning into a temporary TEMP:
//
// TEMP = &foo
//
// so extract `temp`.
let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(start_location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
assigned_place,
);
};
// Consider the borrow not activated to start. When we find an activation, we'll update
// this field.
{
let borrow_data = &mut self.location_map[borrow_index.as_usize()];
borrow_data.activation_location = TwoPhaseActivation::NotActivated;
}
// Insert `temp` into the list of pending activations. From
// now on, we'll be on the lookout for a use of it. Note that
// we are guaranteed that this use will come after the
// assignment.
let old_value = self.pending_activations.insert(temp, borrow_index);
if let Some(old_index) = old_value {
span_bug!(
self.body.source_info(start_location).span,
"found already pending activation for temp: {:?} \
at borrow_index: {:?} with associated data {:?}",
temp,
old_index,
self.location_map[old_index.as_usize()]
);
}
}
}

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
use rustc_hir as hir;

View file

@ -1,8 +1,5 @@
// ignore-tidy-filelength
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::iter;
use std::ops::ControlFlow;

View file

@ -1,10 +1,6 @@
//! Print diagnostics to explain why values are borrowed.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::assert_matches::assert_matches;
use rustc_data_structures::assert_matches;
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;

View file

@ -162,8 +162,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
if count > 10 {
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
}
self.buffer_error(diag);
@ -236,7 +234,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// LL | for (key, value) in dict {
/// | ^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub(super) fn add_moved_or_invoked_closure_note(
&self,
location: Location,
@ -820,7 +817,6 @@ impl UseSpans<'_> {
}
/// Add a span label to the arguments of the closure, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
if let UseSpans::ClosureUse { args_span, .. } = self {
err.subdiagnostic(f(args_span));
@ -829,7 +825,6 @@ impl UseSpans<'_> {
/// Add a span label to the use of the captured variable, if it exists.
/// only adds label to the `path_span`
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_path_only_subdiag(
self,
err: &mut Diag<'_>,
@ -861,7 +856,6 @@ impl UseSpans<'_> {
}
/// Add a subdiagnostic to the use of the captured variable, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_subdiag(
self,
err: &mut Diag<'_>,
@ -1225,8 +1219,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.borrow_spans(span, borrow.reserve_location)
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn explain_captures(
&mut self,
err: &mut Diag<'infcx>,

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::Visitor;

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use core::ops::ControlFlow;
use either::Either;

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::ops::ControlFlow;
use either::Either;

View file

@ -1,9 +1,6 @@
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
//! outlives constraints.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::collections::BTreeMap;
use rustc_data_structures::fx::FxIndexSet;

View file

@ -196,7 +196,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// For generic associated types (GATs) which implied 'static requirement
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
// and the span which bounded to the trait for adding 'static lifetime suggestion
#[allow(rustc::diagnostic_outside_of_impl)]
fn suggest_static_lifetime_for_gat_from_hrtb(
&self,
diag: &mut Diag<'_>,
@ -421,9 +420,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// ```
///
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn report_region_error(
&mut self,
fr: RegionVid,
@ -577,7 +573,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_fnmut_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@ -686,18 +681,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_label(
outlived_fr_span,
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
);
}
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
diag.span_label(
fr_span,
@ -732,9 +721,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
outlived_fr_region_name.highlight_region_name(&mut diag);
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_label(
*span,
format!(
@ -766,7 +752,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
/// | is returning data with lifetime `'b`
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
@ -824,8 +809,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add_static_impl_trait_suggestion(
&self,
diag: &mut Diag<'_>,
@ -966,7 +949,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[instrument(skip(self, err), level = "debug")]
fn suggest_constrain_dyn_trait_in_impl(
&self,
@ -1032,7 +1014,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
);
}
#[allow(rustc::diagnostic_outside_of_impl)]
/// When encountering a lifetime error caused by the return type of a closure, check the
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
/// them. If so, we produce a structured suggestion.
@ -1160,7 +1141,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
#[allow(rustc::diagnostic_outside_of_impl)]
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
let expr = &body.value.peel_blocks();

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::fmt::{self, Display};
use std::iter;

View file

@ -1301,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
(Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators(), borrow, location) {
assert!(borrow.kind.allows_two_phase_borrow());
assert!(borrow.kind.is_two_phase_borrow());
return ControlFlow::Continue(());
}
@ -1464,7 +1464,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if bk.allows_two_phase_borrow() {
if bk.is_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))

View file

@ -287,8 +287,6 @@ pub(crate) fn emit_nll_mir<'tcx>(
Ok(())
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
pub(super) fn dump_annotation<'tcx, 'infcx>(
infcx: &'infcx BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,

View file

@ -264,7 +264,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if bk.allows_two_phase_borrow() {
if bk.is_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))
@ -384,7 +384,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
assert!(borrow.kind.allows_two_phase_borrow());
assert!(borrow.kind.is_two_phase_borrow());
return ControlFlow::Continue(());
}

View file

@ -229,8 +229,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// not ready to process them yet.
// - Then compute the implied bounds. This will adjust
// the `region_bound_pairs` and so forth.
// - After this is done, we'll process the constraints, once
// the `relations` is built.
// - After this is done, we'll register the constraints in
// the `BorrowckInferCtxt`. Checking these constraints is
// handled later by actual borrow checking.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
for ty in unnormalized_input_output_tys {
@ -254,6 +255,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
constraints.push(c)
}
// Currently `implied_outlives_bounds` will normalize the provided
// `Ty`, despite this it's still important to normalize the ty ourselves
// as normalization may introduce new region variables (#136547).
//
// If we do not add implied bounds for the type involving these new
// region variables then we'll wind up with the normalized form of
// the signature having not-wf types due to unsatisfied region
// constraints.
//
// Note: we need this in examples like
// ```
// trait Foo {
@ -262,7 +272,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// }
// impl Foo for () {
// type Bar = ();
// fn foo(&self) ->&() {}
// fn foo(&self) -> &() {}
// }
// ```
// Both &Self::Bar and &() are WF
@ -277,6 +287,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
// Add implied bounds from impl header.
//
// We don't use `assumed_wf_types` to source the entire set of implied bounds for
// a few reasons:
// - `DefiningTy` for closure has the `&'env Self` type while `assumed_wf_types` doesn't
// - We compute implied bounds from the unnormalized types in the `DefiningTy` but do not
// do so for types in impl headers
// - We must compute the normalized signature and then compute implied bounds from that
// in order to connect any unconstrained region vars created during normalization to
// the types of the locals corresponding to the inputs and outputs of the item. (#136547)
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
let result: Result<_, ErrorGuaranteed> = param_env
@ -352,10 +371,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
known_type_outlives_obligations.push(outlives);
}
/// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
/// from this local.
/// Compute and add any implied bounds that come from a given type.
#[instrument(level = "debug", skip(self))]
fn add_implied_bounds(
&mut self,

View file

@ -7,9 +7,8 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
use std::assert_matches::assert_matches;
use itertools::Itertools;
use rustc_data_structures::assert_matches;
use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
use rustc_middle::mir::*;

View file

@ -11,9 +11,6 @@
//! The code in this file doesn't *do anything* with those results; it
//! just returns them for other code to use.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::cell::Cell;
use std::iter;
@ -207,10 +204,10 @@ struct UniversalRegionIndices<'tcx> {
/// `ty::Region` to the internal `RegionVid` we are using. This is
/// used because trait matching and type-checking will feed us
/// region constraints that reference those regions and we need to
/// be able to map them to our internal `RegionVid`. This is
/// basically equivalent to an `GenericArgs`, except that it also
/// contains an entry for `ReStatic` -- it might be nice to just
/// use an args, and then handle `ReStatic` another way.
/// be able to map them to our internal `RegionVid`.
///
/// This is similar to just using `GenericArgs`, except that it contains
/// an entry for `'static`, and also late bound parameters in scope.
indices: FxIndexMap<ty::Region<'tcx>, RegionVid>,
/// The vid assigned to `'static`. Used only for diagnostics.

View file

@ -10,8 +10,8 @@ use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_hir::AttrPath;
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_span::{ErrorGuaranteed, Span, sym};
@ -52,6 +52,8 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
ParsedDescription::Macro,
span,
cx.current_expansion.lint_node_id,
// Doesn't matter what the target actually is here.
Target::Crate,
Some(cx.ecfg.features),
ShouldEmit::ErrorsAndLints,
&meta,

View file

@ -19,9 +19,8 @@ pub(crate) fn expand_compile_error<'cx>(
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
#[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
let guar = cx.dcx().span_err(sp, var.to_string());
cx.resolver.mark_scope_with_compile_error(cx.current_expansion.lint_node_id);
ExpandResult::Ready(DummyResult::any(sp, guar))
}

View file

@ -503,10 +503,6 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
#[expect(
rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages"
)]
let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string());
diag.span(self.span);
diag

View file

@ -3,8 +3,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]

View file

@ -1,12 +1,12 @@
//! The expansion from a test function to the appropriate test struct for libtest
//! Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use std::assert_matches::assert_matches;
use std::iter;
use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_data_structures::assert_matches;
use rustc_errors::{Applicability, Diag, Level};
use rustc_expand::base::*;
use rustc_hir::Attribute;

View file

@ -78,8 +78,6 @@ type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), Err
/// The returned bool indicates whether an applicable suggestion has already been
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
/// indicates that an ast error was encountered.
// FIXME(Nilstrieb) Make this function setup translatable
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: Box<ast::Expr>,

View file

@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs
index 1e336bf..35e6f54 100644
--- a/coretests/tests/lib.rs
+++ b/coretests/tests/lib.rs
@@ -2,5 +2,4 @@
@@ -2,4 +2,3 @@
// tidy-alphabetical-start
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644

View file

@ -1,6 +1,4 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
// Note: please avoid adding other feature gates where possible
#![feature(rustc_private)]
// Only used to define intrinsics in `compiler_builtins.rs`.

View file

@ -1,9 +1,8 @@
use std::assert_matches::assert_matches;
use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::Instance;
use rustc_middle::ty::layout::TyAndLayout;

View file

@ -1,6 +1,7 @@
//! Set and unset common attributes on LLVM values.
use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr, RtsanSetting};
use rustc_hir::def_id::DefId;
use rustc_hir::find_attr;
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
};
@ -470,9 +471,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
{
to_add.push(create_alloc_family_attr(cx.llcx));
if let Some(instance) = instance
&& let Some(zv) =
tcx.get_attr(instance.def_id(), rustc_span::sym::rustc_allocator_zeroed_variant)
&& let Some(name) = zv.value_str()
&& let Some(name) = find_attr!(tcx.get_all_attrs(instance.def_id()), rustc_hir::attrs::AttributeKind::RustcAllocatorZeroedVariant {name} => name)
{
to_add.push(llvm::CreateAttrStringValue(
cx.llcx,
@ -517,16 +516,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
to_add.push(llvm::CreateAllocKindAttr(cx.llcx, AllocKindFlags::Free));
// applies to argument place instead of function place
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
let attrs: &[_] = if llvm_util::get_version() >= (21, 0, 0) {
// "Does not capture provenance" means "if the function call stashes the pointer somewhere,
// accessing that pointer after the function returns is UB". That is definitely the case here since
// freeing will destroy the provenance.
let captures_addr = AttributeKind::CapturesAddress.create_attr(cx.llcx);
&[allocated_pointer, captures_addr]
} else {
&[allocated_pointer]
};
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), attrs);
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
}
if let Some(align) = codegen_fn_attrs.alignment {
llvm::set_alignment(llfn, align);

View file

@ -55,6 +55,10 @@ impl<'ll> OffloadGlobals<'ll> {
let init_ty = cx.type_func(&[], cx.type_void());
let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty);
// We want LLVM's openmp-opt pass to pick up and optimize this module, since it covers both
// openmp and offload optimizations.
llvm::add_module_flag_u32(cx.llmod(), llvm::ModuleFlagMergeBehavior::Max, "openmp", 51);
OffloadGlobals {
launcher_fn,
launcher_ty,

View file

@ -1,9 +1,9 @@
use std::assert_matches::assert_matches;
use std::sync::Arc;
use itertools::Itertools;
use rustc_abi::Align;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::FxIndexMap;
use rustc_index::IndexVec;
use rustc_middle::ty::TyCtxt;

View file

@ -1,4 +1,3 @@
use std::assert_matches::assert_matches;
use std::cmp::Ordering;
use std::ffi::c_uint;
use std::ptr;
@ -13,6 +12,7 @@ use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphizati
use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::assert_matches;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::{self as hir};
use rustc_middle::mir::BinOp;
@ -560,6 +560,12 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
return Ok(());
}
sym::amdgpu_dispatch_ptr => {
let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]);
// Relying on `LLVMBuildPointerCast` to produce an addrspacecast
self.pointercast(val, self.type_ptr())
}
_ if name.as_str().starts_with("simd_") => {
// Unpack non-power-of-2 #[repr(packed, simd)] arguments.
// This gives them the expected layout of a regular #[repr(simd)] vector.

View file

@ -1,4 +1,3 @@
use std::assert_matches::assert_matches;
use std::marker::PhantomData;
use std::panic::AssertUnwindSafe;
use std::path::{Path, PathBuf};
@ -8,6 +7,7 @@ use std::{fs, io, mem, str, thread};
use rustc_abi::Size;
use rustc_ast::attr;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::jobserver::{self, Acquired};
use rustc_data_structures::memmap::Mmap;

View file

@ -335,6 +335,24 @@ fn process_builtin_attrs(
AttributeKind::InstructionSet(instruction_set) => {
codegen_fn_attrs.instruction_set = Some(*instruction_set)
}
AttributeKind::RustcAllocator => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR
}
AttributeKind::RustcDeallocator => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR
}
AttributeKind::RustcReallocator => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR
}
AttributeKind::RustcAllocatorZeroed => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
AttributeKind::RustcNounwind => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND
}
AttributeKind::RustcOffloadKernel => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
}
_ => {}
}
}
@ -344,20 +362,10 @@ fn process_builtin_attrs(
};
match name {
sym::rustc_allocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR,
sym::rustc_nounwind => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND,
sym::rustc_reallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR,
sym::rustc_deallocator => codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR,
sym::rustc_allocator_zeroed => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
sym::patchable_function_entry => {
codegen_fn_attrs.patchable_function_entry =
parse_patchable_function_entry(tcx, attr);
}
sym::rustc_offload_kernel => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
}
_ => {}
}
}

View file

@ -1,6 +1,4 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(file_buffered)]

View file

@ -112,6 +112,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
| sym::unreachable
| sym::cold_path
| sym::breakpoint
| sym::amdgpu_dispatch_ptr
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid
| sym::assert_inhabited

View file

@ -1,7 +1,7 @@
use std::assert_matches::assert_matches;
use std::ops::Deref;
use rustc_abi::{Align, Scalar, Size, WrappingRange};
use rustc_data_structures::assert_matches;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};

View file

@ -140,9 +140,9 @@ const_eval_incompatible_return_types =
const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this borrow of an interior mutable value refers to such a temporary
.note = Temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
.help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_intern_kind = {$kind ->
[static] static
@ -225,9 +225,9 @@ const_eval_modified_global =
const_eval_mutable_borrow_escaping =
mutable borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this mutable borrow refers to such a temporary
.note = Temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = To avoid accidentally creating global mutable state, such temporaries must be immutable
.help = If you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
.note = temporaries in constants and statics can have their lifetime extended until the end of the program
.note2 = to avoid accidentally creating global mutable state, such temporaries must be immutable
.help = if you really want global mutable state, try replacing the temporary by an interior mutable `static` or a `static mut`
const_eval_mutable_ptr_in_final = encountered mutable pointer in final value of {const_eval_intern_kind}

View file

@ -1,11 +1,11 @@
//! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
use std::assert_matches::assert_matches;
use std::borrow::Cow;
use std::mem;
use std::num::NonZero;
use std::ops::Deref;
use rustc_data_structures::assert_matches;
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;

View file

@ -125,9 +125,6 @@ pub(crate) struct FnCallNonConst<'tcx> {
}
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
let tcx = ccx.tcx;
let caller = ccx.def_id();

View file

@ -394,8 +394,10 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
typing_env: ty::TypingEnv<'tcx>,
) -> Result<R, ErrorHandled> {
let def = cid.instance.def.def_id();
let is_static = tcx.is_static(def);
// #[type_const] don't have bodys
debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def);
let is_static = tcx.is_static(def);
let mut ecx = InterpCx::new(
tcx,
tcx.def_span(def),

View file

@ -1,6 +1,6 @@
use rustc_abi::FieldIdx;
use rustc_ast::Mutability;
use rustc_hir::LangItem;
use rustc_middle::mir::interpret::CtfeProvenance;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Const, ScalarInt, Ty};
@ -8,7 +8,8 @@ use rustc_span::{Symbol, sym};
use crate::const_eval::CompileTimeMachine;
use crate::interpret::{
Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Writeable, interp_ok,
CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, MemoryKind, Scalar, Writeable,
interp_ok,
};
impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
@ -35,6 +36,7 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok((variant_id, self.project_downcast(&field_dest, variant_id)?))
};
let ptr_bit_width = || self.tcx.data_layout.pointer_size().bits();
match field.name {
sym::kind => {
let variant_index = match ty.kind() {
@ -64,17 +66,65 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
variant
}
// For now just merge all primitives into one `Leaf` variant with no data
ty::Uint(_) | ty::Int(_) | ty::Float(_) | ty::Char | ty::Bool => {
downcast(sym::Leaf)?.0
ty::Bool => {
let (variant, _variant_place) = downcast(sym::Bool)?;
variant
}
ty::Char => {
let (variant, _variant_place) = downcast(sym::Char)?;
variant
}
ty::Int(int_ty) => {
let (variant, variant_place) = downcast(sym::Int)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_int_type_info(
place,
int_ty.bit_width().unwrap_or_else(/* isize */ ptr_bit_width),
true,
)?;
variant
}
ty::Uint(uint_ty) => {
let (variant, variant_place) = downcast(sym::Int)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_int_type_info(
place,
uint_ty.bit_width().unwrap_or_else(/* usize */ ptr_bit_width),
false,
)?;
variant
}
ty::Float(float_ty) => {
let (variant, variant_place) = downcast(sym::Float)?;
let place = self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_float_type_info(place, float_ty.bit_width())?;
variant
}
ty::Str => {
let (variant, _variant_place) = downcast(sym::Str)?;
variant
}
ty::Ref(_, ty, mutability) => {
let (variant, variant_place) = downcast(sym::Reference)?;
let reference_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_reference_type_info(reference_place, *ty, *mutability)?;
variant
}
ty::RawPtr(ty, mutability) => {
let (variant, variant_place) = downcast(sym::Pointer)?;
let pointer_place =
self.project_field(&variant_place, FieldIdx::ZERO)?;
self.write_pointer_type_info(pointer_place, *ty, *mutability)?;
variant
}
ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::UnsafeBinder(..)
@ -203,4 +253,97 @@ impl<'tcx> InterpCx<'tcx, CompileTimeMachine<'tcx>> {
interp_ok(())
}
fn write_int_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
bit_width: u64,
signed: bool,
) -> InterpResult<'tcx> {
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
sym::bits => self.write_scalar(
Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
&field_place,
)?,
sym::signed => self.write_scalar(Scalar::from_bool(signed), &field_place)?,
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
fn write_float_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
bit_width: u64,
) -> InterpResult<'tcx> {
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
sym::bits => self.write_scalar(
Scalar::from_u32(bit_width.try_into().expect("bit_width overflowed")),
&field_place,
)?,
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
pub(crate) fn write_reference_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
mutability: Mutability,
) -> InterpResult<'tcx> {
// Iterate over all fields of `type_info::Reference`.
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
// Write the `TypeId` of the reference's inner type to the `ty` field.
sym::pointee => self.write_type_id(ty, &field_place)?,
// Write the boolean representing the reference's mutability to the `mutable` field.
sym::mutable => {
self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
pub(crate) fn write_pointer_type_info(
&mut self,
place: impl Writeable<'tcx, CtfeProvenance>,
ty: Ty<'tcx>,
mutability: Mutability,
) -> InterpResult<'tcx> {
// Iterate over all fields of `type_info::Pointer`.
for (field_idx, field) in
place.layout().ty.ty_adt_def().unwrap().non_enum_variant().fields.iter_enumerated()
{
let field_place = self.project_field(&place, field_idx)?;
match field.name {
// Write the `TypeId` of the pointer's inner type to the `ty` field.
sym::pointee => self.write_type_id(ty, &field_place)?,
// Write the boolean representing the pointer's mutability to the `mutable` field.
sym::mutable => {
self.write_scalar(Scalar::from_bool(mutability.is_mut()), &field_place)?
}
other => span_bug!(self.tcx.def_span(field.did), "unimplemented field {other}"),
}
}
interp_ok(())
}
}

View file

@ -1,10 +1,10 @@
//! Manages calling a concrete function (with known MIR body) with argument passing,
//! and returning the return value to the caller.
use std::assert_matches::assert_matches;
use std::borrow::Cow;
use either::{Left, Right};
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
use rustc_data_structures::assert_matches;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};

View file

@ -1,8 +1,7 @@
use std::assert_matches::assert_matches;
use rustc_abi::{FieldIdx, Integer};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::{Float, FloatConvert};
use rustc_data_structures::assert_matches;
use rustc_middle::mir::CastKind;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::ty::adjustment::PointerCoercion;

View file

@ -1,7 +1,6 @@
use std::assert_matches::debug_assert_matches;
use either::{Left, Right};
use rustc_abi::{Align, HasDataLayout, Size, TargetDataLayout};
use rustc_data_structures::debug_assert_matches;
use rustc_errors::DiagCtxtHandle;
use rustc_hir::def_id::DefId;
use rustc_hir::limit::Limit;
@ -233,7 +232,6 @@ pub fn format_interp_error<'tcx>(dcx: DiagCtxtHandle<'_>, e: InterpErrorInfo<'tc
backtrace.print_backtrace();
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
// label and arguments from the InterpError.
#[allow(rustc::untranslatable_diagnostic)]
let mut diag = dcx.struct_allow("");
let msg = e.diagnostic_message();
e.add_args(&mut diag);

View file

@ -4,10 +4,9 @@
mod simd;
use std::assert_matches::assert_matches;
use rustc_abi::{FIRST_VARIANT, FieldIdx, HasDataLayout, Size, VariantIdx};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_data_structures::assert_matches;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};

View file

@ -2,6 +2,7 @@ use either::Either;
use rustc_abi::{BackendRepr, Endian};
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
use rustc_apfloat::{Float, Round};
use rustc_data_structures::assert_matches;
use rustc_middle::mir::interpret::{InterpErrorKind, Pointer, UndefinedBehaviorInfo};
use rustc_middle::ty::{FloatTy, ScalarInt, SimdAlign};
use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
@ -10,7 +11,7 @@ use tracing::trace;
use super::{
ImmTy, InterpCx, InterpResult, Machine, MinMax, MulAddType, OpTy, PlaceTy, Provenance, Scalar,
Size, TyAndLayout, assert_matches, interp_ok, throw_ub_format,
Size, TyAndLayout, interp_ok, throw_ub_format,
};
use crate::interpret::Writeable;

View file

@ -6,7 +6,6 @@
//! integer. It is crucial that these operations call `check_align` *before*
//! short-circuiting the empty case!
use std::assert_matches::assert_matches;
use std::borrow::{Borrow, Cow};
use std::cell::Cell;
use std::collections::VecDeque;
@ -14,6 +13,7 @@ use std::{fmt, ptr};
use rustc_abi::{Align, HasDataLayout, Size};
use rustc_ast::Mutability;
use rustc_data_structures::assert_matches;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};

View file

@ -1,11 +1,10 @@
//! Functions concerning immediate values and operands, and reading from operands.
//! All high-level functions to read from memory work on operands as sources.
use std::assert_matches::assert_matches;
use either::{Either, Left, Right};
use rustc_abi as abi;
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_data_structures::assert_matches;
use rustc_hir::def::Namespace;
use rustc_middle::mir::interpret::ScalarSizeMismatch;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout};

View file

@ -2,10 +2,9 @@
//! into a place.
//! All high-level functions to write to memory work on places as destinations.
use std::assert_matches::assert_matches;
use either::{Either, Left, Right};
use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_data_structures::assert_matches;
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, mir, span_bug};

View file

@ -218,7 +218,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// A fresh reference was created, make sure it gets retagged.
let val = M::retag_ptr_value(
self,
if borrow_kind.allows_two_phase_borrow() {
if borrow_kind.is_two_phase_borrow() {
mir::RetagKind::TwoPhase
} else {
mir::RetagKind::Default

View file

@ -1,5 +1,4 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![feature(array_try_map)]
#![feature(assert_matches)]
#![feature(box_patterns)]

View file

@ -28,3 +28,18 @@ macro_rules! define_stable_id_collections {
pub type $entry_name<'a, T> = $crate::fx::IndexEntry<'a, $key, T>;
};
}
pub mod default {
use super::{FxBuildHasher, FxHashMap, FxHashSet};
// FIXME: These two functions will become unnecessary after
// <https://github.com/rust-lang/rustc-hash/pull/63> lands and we start using the corresponding
// `rustc-hash` version. After that we can use `Default::default()` instead.
pub const fn fx_hash_map<K, V>() -> FxHashMap<K, V> {
FxHashMap::with_hasher(FxBuildHasher)
}
pub const fn fx_hash_set<V>() -> FxHashSet<V> {
FxHashSet::with_hasher(FxBuildHasher)
}
}

View file

@ -8,7 +8,6 @@
//! Typical examples would include: minimum element in SCC, maximum element
//! reachable from it, etc.
use std::assert_matches::debug_assert_matches;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::Range;
@ -16,6 +15,7 @@ use std::ops::Range;
use rustc_index::{Idx, IndexSlice, IndexVec};
use tracing::{debug, instrument, trace};
use crate::debug_assert_matches;
use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, NumEdges, Successors};

View file

@ -18,6 +18,8 @@
#![feature(assert_matches)]
#![feature(auto_traits)]
#![feature(cfg_select)]
#![feature(const_default)]
#![feature(const_trait_impl)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(extend_one)]
@ -36,6 +38,11 @@
#![feature(unwrap_infallible)]
// tidy-alphabetical-end
// Temporarily re-export `assert_matches!`, so that the rest of the compiler doesn't
// have to worry about it being moved to a different module in std during stabilization.
// FIXME(#151359): Remove this when `feature(assert_matches)` is stable in stage0.
// (This doesn't necessarily need to be fixed during the beta bump itself.)
pub use std::assert_matches::{assert_matches, debug_assert_matches};
use std::fmt;
pub use atomic_ref::AtomicRef;

View file

@ -8,7 +8,7 @@ use std::hash::Hash;
use std::iter::{Product, Sum};
use std::ops::Index;
use rustc_hash::{FxHashMap, FxHashSet};
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
use rustc_macros::{Decodable_NoContext, Encodable_NoContext};
use crate::fingerprint::Fingerprint;
@ -241,10 +241,10 @@ pub struct UnordSet<V: Eq + Hash> {
impl<V: Eq + Hash> UnordCollection for UnordSet<V> {}
impl<V: Eq + Hash> Default for UnordSet<V> {
impl<V: Eq + Hash> const Default for UnordSet<V> {
#[inline]
fn default() -> Self {
Self { inner: FxHashSet::default() }
Self { inner: FxHashSet::with_hasher(FxBuildHasher) }
}
}
@ -438,10 +438,10 @@ pub struct UnordMap<K: Eq + Hash, V> {
impl<K: Eq + Hash, V> UnordCollection for UnordMap<K, V> {}
impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
impl<K: Eq + Hash, V> const Default for UnordMap<K, V> {
#[inline]
fn default() -> Self {
Self { inner: FxHashMap::default() }
Self { inner: FxHashMap::with_hasher(FxBuildHasher) }
}
}

View file

@ -5,6 +5,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
anstyle = "1.0.13"
jiff = { version = "0.2.5", default-features = false, features = ["std"] }
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
@ -28,6 +29,7 @@ rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_interface = { path = "../rustc_interface" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint = { path = "../rustc_lint" }
rustc_log = { path = "../rustc_log" }
rustc_macros = { path = "../rustc_macros" }

View file

@ -97,7 +97,6 @@ impl Expander {
/// **Note:** This function doesn't interpret argument 0 in any special way.
/// If this function is intended to be used with command line arguments,
/// `argv[0]` must be removed prior to calling it manually.
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> {
let mut expander = Expander::default();
let mut result = Ok(());

View file

@ -0,0 +1,159 @@
//! This module provides a syntax highlighter for Rust code.
//! It is used by the `rustc --explain` command.
//!
//! The syntax highlighter uses `rustc_lexer`'s `tokenize`
//! function to parse the Rust code into a `Vec` of tokens.
//! The highlighter then highlights the tokens in the `Vec`,
//! and writes the highlighted output to the buffer.
use std::io::{self, Write};
use anstyle::{AnsiColor, Color, Effects, Style};
use rustc_lexer::{LiteralKind, strip_shebang, tokenize};
const PRIMITIVE_TYPES: &'static [&str] = &[
"i8", "i16", "i32", "i64", "i128", "isize", // signed integers
"u8", "u16", "u32", "u64", "u128", "usize", // unsigned integers
"f32", "f64", // floating point
"char", "bool", // others
];
const KEYWORDS: &'static [&str] = &[
"static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while", "as",
"async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern",
"false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub",
"ref",
];
const STR_LITERAL_COLOR: AnsiColor = AnsiColor::Green;
const OTHER_LITERAL_COLOR: AnsiColor = AnsiColor::BrightRed;
const DERIVE_COLOR: AnsiColor = AnsiColor::BrightRed;
const KEYWORD_COLOR: AnsiColor = AnsiColor::BrightMagenta;
const TYPE_COLOR: AnsiColor = AnsiColor::Yellow;
const FUNCTION_COLOR: AnsiColor = AnsiColor::Blue;
const USE_COLOR: AnsiColor = AnsiColor::BrightMagenta;
const PRIMITIVE_TYPE_COLOR: AnsiColor = AnsiColor::Cyan;
/// Highlight a Rust code string and write the highlighted
/// output to the buffer. It serves as a wrapper around
/// `Highlighter::highlight_rustc_lexer`. It is passed to
/// `write_anstream_buf` in the `lib.rs` file.
pub fn highlight(code: &str, buf: &mut Vec<u8>) -> io::Result<()> {
let mut highlighter = Highlighter::default();
highlighter.highlight_rustc_lexer(code, buf)
}
/// A syntax highlighter for Rust code
/// It is used by the `rustc --explain` command.
#[derive(Default)]
pub struct Highlighter {
/// Used to track if the previous token was a token
/// that warrants the next token to be colored differently
///
/// For example, the keyword `fn` requires the next token
/// (the function name) to be colored differently.
prev_was_special: bool,
/// Used to track the length of tokens that have been
/// written so far. This is used to find the original
/// lexeme for a token from the code string.
len_accum: usize,
}
impl Highlighter {
/// Create a new highlighter
pub fn new() -> Self {
Self::default()
}
/// Highlight a Rust code string and write the highlighted
/// output to the buffer.
pub fn highlight_rustc_lexer(&mut self, code: &str, buf: &mut Vec<u8>) -> io::Result<()> {
use rustc_lexer::TokenKind;
// Remove shebang from code string
let stripped_idx = strip_shebang(code).unwrap_or(0);
let stripped_code = &code[stripped_idx..];
self.len_accum = stripped_idx;
let len_accum = &mut self.len_accum;
let tokens = tokenize(stripped_code, rustc_lexer::FrontmatterAllowed::No);
for token in tokens {
let len = token.len as usize;
// If the previous token was a special token, and this token is
// not a whitespace token, then it should be colored differently
let token_str = &code[*len_accum..*len_accum + len];
if self.prev_was_special {
if token_str != " " {
self.prev_was_special = false;
}
let style = Style::new().fg_color(Some(Color::Ansi(AnsiColor::Blue)));
write!(buf, "{style}{token_str}{style:#}")?;
*len_accum += len;
continue;
}
match token.kind {
TokenKind::Ident => {
let mut style = Style::new();
// Match if an identifier is a (well-known) keyword
if KEYWORDS.contains(&token_str) {
if token_str == "fn" {
self.prev_was_special = true;
}
style = style.fg_color(Some(Color::Ansi(KEYWORD_COLOR)));
}
// The `use` keyword is colored differently
if matches!(token_str, "use") {
style = style.fg_color(Some(Color::Ansi(USE_COLOR)));
}
// This heuristic test is to detect if the identifier is
// a function call. If it is, then the function identifier is
// colored differently.
if code[*len_accum..*len_accum + len + 1].ends_with('(') {
style = style.fg_color(Some(Color::Ansi(FUNCTION_COLOR)));
}
// The `derive` keyword is colored differently.
if token_str == "derive" {
style = style.fg_color(Some(Color::Ansi(DERIVE_COLOR)));
}
// This heuristic test is to detect if the identifier is
// a type. If it is, then the identifier is colored differently.
if matches!(token_str.chars().next().map(|c| c.is_uppercase()), Some(true)) {
style = style.fg_color(Some(Color::Ansi(TYPE_COLOR)));
}
// This if statement is to detect if the identifier is a primitive type.
if PRIMITIVE_TYPES.contains(&token_str) {
style = style.fg_color(Some(Color::Ansi(PRIMITIVE_TYPE_COLOR)));
}
write!(buf, "{style}{token_str}{style:#}")?;
}
// Color literals
TokenKind::Literal { kind, suffix_start: _ } => {
// Strings -> Green
// Chars -> Green
// Raw strings -> Green
// C strings -> Green
// Byte Strings -> Green
// Other literals -> Bright Red (Orage-esque)
let style = match kind {
LiteralKind::Str { terminated: _ }
| LiteralKind::Char { terminated: _ }
| LiteralKind::RawStr { n_hashes: _ }
| LiteralKind::CStr { terminated: _ } => {
Style::new().fg_color(Some(Color::Ansi(STR_LITERAL_COLOR)))
}
_ => Style::new().fg_color(Some(Color::Ansi(OTHER_LITERAL_COLOR))),
};
write!(buf, "{style}{token_str}{style:#}")?;
}
_ => {
// All other tokens are dimmed
let style = Style::new()
.fg_color(Some(Color::Ansi(AnsiColor::BrightWhite)))
.effects(Effects::DIMMED);
write!(buf, "{style}{token_str}{style:#}")?;
}
}
*len_accum += len;
}
Ok(())
}
}

View file

@ -5,7 +5,6 @@
//! This API is completely unstable and subject to change.
// tidy-alphabetical-start
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![feature(decl_macro)]
#![feature(panic_backtrace_config)]
#![feature(panic_update_hook)]
@ -86,6 +85,7 @@ pub mod args;
pub mod pretty;
#[macro_use]
mod print;
pub mod highlighter;
mod session_diagnostics;
// Keep the OS parts of this `cfg` in sync with the `cfg` on the `libc`
@ -228,8 +228,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
let args = args::arg_expand_all(&default_early_dcx, at_args);
let Some(matches) = handle_options(&default_early_dcx, &args) else {
return;
let (matches, help_only) = match handle_options(&default_early_dcx, &args) {
HandledOptions::None => return,
HandledOptions::Normal(matches) => (matches, false),
HandledOptions::HelpOnly(matches) => (matches, true),
};
let sopts = config::build_session_options(&mut default_early_dcx, &matches);
@ -291,12 +293,16 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
return early_exit();
}
// We have now handled all help options, exit
if help_only {
return early_exit();
}
if print_crate_info(codegen_backend, sess, has_input) == Compilation::Stop {
return early_exit();
}
if !has_input {
#[allow(rustc::diagnostic_outside_of_impl)]
sess.dcx().fatal("no input filename given"); // this is fatal
}
@ -521,7 +527,11 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
let mdstream = markdown::MdStream::parse_str(content);
let bufwtr = markdown::create_stdout_bufwtr();
let mut mdbuf = Vec::new();
if mdstream.write_anstream_buf(&mut mdbuf).is_ok() { Some((bufwtr, mdbuf)) } else { None }
if mdstream.write_anstream_buf(&mut mdbuf, Some(&highlighter::highlight)).is_ok() {
Some((bufwtr, mdbuf))
} else {
None
}
};
// Try to print via the pager, pretty output if possible.
@ -608,7 +618,6 @@ fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) {
safe_println!("{}", String::from_utf8(v).unwrap());
}
Input::Str { .. } => {
#[allow(rustc::diagnostic_outside_of_impl)]
sess.dcx().fatal("cannot list metadata for stdin");
}
}
@ -835,7 +844,6 @@ fn print_crate_info(
sess.apple_deployment_target().fmt_pretty(),
)
} else {
#[allow(rustc::diagnostic_outside_of_impl)]
sess.dcx().fatal("only Apple targets currently support deployment version info")
}
}
@ -1097,7 +1105,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
// Don't handle -W help here, because we might first load additional lints.
let debug_flags = matches.opt_strs("Z");
if debug_flags.iter().any(|x| *x == "help") {
describe_debug_flags();
describe_unstable_flags();
return true;
}
@ -1137,8 +1145,8 @@ fn get_backend_from_raw_matches(
get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
}
fn describe_debug_flags() {
safe_println!("\nAvailable options:\n");
fn describe_unstable_flags() {
safe_println!("\nAvailable unstable options:\n");
print_flag_list("-Z", config::Z_OPTIONS);
}
@ -1162,6 +1170,16 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
}
}
pub enum HandledOptions {
/// Parsing failed, or we parsed a flag causing an early exit
None,
/// Successful parsing
Normal(getopts::Matches),
/// Parsing succeeded, but we received one or more 'help' flags
/// The compiler should proceed only until a possible `-W help` flag has been processed
HelpOnly(getopts::Matches),
}
/// Process command line options. Emits messages as appropriate. If compilation
/// should continue, returns a getopts::Matches object parsed from args,
/// otherwise returns `None`.
@ -1189,7 +1207,7 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
/// This does not need to be `pub` for rustc itself, but @chaosite needs it to
/// be public when using rustc as a library, see
/// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> HandledOptions {
// Parse with *all* options defined in the compiler, we don't worry about
// option stability here we just want to parse as much as possible.
let mut options = getopts::Options::new();
@ -1235,26 +1253,69 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
// (unstable option being used on stable)
nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups());
if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
// Only show unstable options in --help if we accept unstable options.
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
return None;
// Handle the special case of -Wall.
let wall = matches.opt_strs("W");
if wall.iter().any(|x| *x == "all") {
print_wall_help();
return HandledOptions::None;
}
if describe_flag_categories(early_dcx, &matches) {
return None;
if handle_help(&matches, args) {
return HandledOptions::HelpOnly(matches);
}
if matches.opt_strs("C").iter().any(|x| x == "passes=list") {
get_backend_from_raw_matches(early_dcx, &matches).print_passes();
return HandledOptions::None;
}
if matches.opt_present("version") {
version!(early_dcx, "rustc", &matches);
return None;
return HandledOptions::None;
}
warn_on_confusing_output_filename_flag(early_dcx, &matches, args);
Some(matches)
HandledOptions::Normal(matches)
}
/// Handle help options in the order they are provided, ignoring other flags. Returns if any options were handled
/// Handled options:
/// - `-h`/`--help`/empty arguments
/// - `-Z help`
/// - `-C help`
/// NOTE: `-W help` is NOT handled here, as additional lints may be loaded.
pub fn handle_help(matches: &getopts::Matches, args: &[String]) -> bool {
let opt_pos = |opt| matches.opt_positions(opt).first().copied();
let opt_help_pos = |opt| {
matches
.opt_strs_pos(opt)
.iter()
.filter_map(|(pos, oval)| if oval == "help" { Some(*pos) } else { None })
.next()
};
let help_pos = if args.is_empty() { Some(0) } else { opt_pos("h").or_else(|| opt_pos("help")) };
let zhelp_pos = opt_help_pos("Z");
let chelp_pos = opt_help_pos("C");
let print_help = || {
// Only show unstable options in --help if we accept unstable options.
let unstable_enabled = nightly_options::is_unstable_enabled(&matches);
let nightly_build = nightly_options::match_is_nightly_build(&matches);
usage(matches.opt_present("verbose"), unstable_enabled, nightly_build);
};
let mut helps = [
(help_pos, &print_help as &dyn Fn()),
(zhelp_pos, &describe_unstable_flags),
(chelp_pos, &describe_codegen_flags),
];
helps.sort_by_key(|(pos, _)| pos.clone());
let mut printed_any = false;
for printer in helps.iter().filter_map(|(pos, func)| pos.is_some().then_some(func)) {
printer();
printed_any = true;
}
printed_any
}
/// Warn if `-o` is used without a space between the flag name and the value

View file

@ -244,13 +244,6 @@ type FluentId = Cow<'static, str>;
pub enum SubdiagMessage {
/// Non-translatable diagnostic message.
Str(Cow<'static, str>),
/// Translatable message which has already been translated eagerly.
///
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
/// be instantiated multiple times with different values. These subdiagnostics' messages
/// are translated when they are added to the parent diagnostic, producing this variant of
/// `DiagMessage`.
Translated(Cow<'static, str>),
/// Identifier of a Fluent message. Instances of this variant are generated by the
/// `Subdiagnostic` derive.
FluentIdentifier(FluentId),
@ -285,15 +278,13 @@ impl From<Cow<'static, str>> for SubdiagMessage {
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
#[rustc_diagnostic_item = "DiagMessage"]
pub enum DiagMessage {
/// Non-translatable diagnostic message.
Str(Cow<'static, str>),
/// Translatable message which has been already translated.
/// Non-translatable diagnostic message or a message that has been translated eagerly.
///
/// Some diagnostics have repeated subdiagnostics where the same interpolated variables would
/// be instantiated multiple times with different values. These subdiagnostics' messages
/// are translated when they are added to the parent diagnostic, producing this variant of
/// `DiagMessage`.
Translated(Cow<'static, str>),
/// are translated when they are added to the parent diagnostic. This is one of the ways
/// this variant of `DiagMessage` is produced.
Str(Cow<'static, str>),
/// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic
/// message. Yet to be translated.
///
@ -311,7 +302,6 @@ impl DiagMessage {
pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self {
let attr = match sub {
SubdiagMessage::Str(s) => return DiagMessage::Str(s),
SubdiagMessage::Translated(s) => return DiagMessage::Translated(s),
SubdiagMessage::FluentIdentifier(id) => {
return DiagMessage::FluentIdentifier(id, None);
}
@ -320,7 +310,6 @@ impl DiagMessage {
match self {
DiagMessage::Str(s) => DiagMessage::Str(s.clone()),
DiagMessage::Translated(s) => DiagMessage::Translated(s.clone()),
DiagMessage::FluentIdentifier(id, _) => {
DiagMessage::FluentIdentifier(id.clone(), Some(attr))
}
@ -329,7 +318,7 @@ impl DiagMessage {
pub fn as_str(&self) -> Option<&str> {
match self {
DiagMessage::Translated(s) | DiagMessage::Str(s) => Some(s),
DiagMessage::Str(s) => Some(s),
DiagMessage::FluentIdentifier(_, _) => None,
}
}
@ -360,7 +349,6 @@ impl From<DiagMessage> for SubdiagMessage {
fn from(val: DiagMessage) -> Self {
match val {
DiagMessage::Str(s) => SubdiagMessage::Str(s),
DiagMessage::Translated(s) => SubdiagMessage::Translated(s),
DiagMessage::FluentIdentifier(id, None) => SubdiagMessage::FluentIdentifier(id),
// There isn't really a sensible behaviour for this because it loses information but
// this is the most sensible of the behaviours.

View file

@ -538,7 +538,6 @@ macro_rules! with_fn {
}
impl<'a, G: EmissionGuarantee> Diag<'a, G> {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn new(dcx: DiagCtxtHandle<'a>, level: Level, message: impl Into<DiagMessage>) -> Self {
Self::new_diagnostic(dcx, DiagInner::new(level, message))
@ -566,7 +565,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
///
/// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) {
assert!(
@ -584,7 +582,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// This function still gives an emission guarantee, the guarantee is now just that it exits fatally.
/// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another
/// might now be ignored.
#[rustc_lint_diagnostics]
#[track_caller]
pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> {
assert!(
@ -613,7 +610,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
#[rustc_lint_diagnostics]
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
let msg = self.subdiagnostic_message_to_diagnostic_message(label);
self.span.push_span_label(span, msg);
@ -623,7 +619,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_labels,
/// Labels all the given spans with the provided label.
/// See [`Self::span_label()`] for more information.
#[rustc_lint_diagnostics]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item = Span>, label: &str) -> &mut Self {
for span in spans {
self.span_label(span, label.to_string());
@ -631,7 +626,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
#[rustc_lint_diagnostics]
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.span(after);
@ -647,7 +641,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
}
#[rustc_lint_diagnostics]
pub fn note_expected_found(
&mut self,
expected_label: &str,
@ -665,7 +658,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
)
}
#[rustc_lint_diagnostics]
pub fn note_expected_found_extra(
&mut self,
expected_label: &str,
@ -711,7 +703,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
}
#[rustc_lint_diagnostics]
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
StringPart::normal(format!("`{name}` from trait: `")),
@ -723,19 +714,16 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_note,
/// Add a note attached to this diagnostic.
#[rustc_lint_diagnostics]
pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new());
self
} }
#[rustc_lint_diagnostics]
pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_span_note(
&mut self,
span: impl Into<MultiSpan>,
@ -746,7 +734,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
}
/// This is like [`Diag::note()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new());
self
@ -755,7 +742,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_note,
/// Prints the span with a note above it.
/// This is like [`Diag::note()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_note(
&mut self,
sp: impl Into<MultiSpan>,
@ -767,7 +753,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints the span with a note above it.
/// This is like [`Diag::note_once()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
@ -779,7 +764,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_warn,
/// Add a warning attached to this diagnostic.
#[rustc_lint_diagnostics]
pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new());
self
@ -787,7 +771,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints the span with a warning above it.
/// This is like [`Diag::warn()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
@ -799,28 +782,24 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_help,
/// Add a help message attached to this diagnostic.
#[rustc_lint_diagnostics]
pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::Help, msg, MultiSpan::new());
self
} }
/// This is like [`Diag::help()`], but it's only printed once.
#[rustc_lint_diagnostics]
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(Level::OnceHelp, msg, MultiSpan::new());
self
}
/// Add a help message attached to this diagnostic with a customizable highlighted message.
#[rustc_lint_diagnostics]
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
self
}
/// Add a help message attached to this diagnostic with a customizable highlighted message.
#[rustc_lint_diagnostics]
pub fn highlighted_span_help(
&mut self,
span: impl Into<MultiSpan>,
@ -833,7 +812,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_help,
/// Prints the span with some help above it.
/// This is like [`Diag::help()`], but it gets its own span.
#[rustc_lint_diagnostics]
pub fn span_help(
&mut self,
sp: impl Into<MultiSpan>,
@ -846,7 +824,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Disallow attaching suggestions to this diagnostic.
/// Any suggestions attached e.g. with the `span_suggestion_*` methods
/// (before and after the call to `disable_suggestions`) will be ignored.
#[rustc_lint_diagnostics]
pub fn disable_suggestions(&mut self) -> &mut Self {
self.suggestions = Suggestions::Disabled;
self
@ -856,7 +833,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
///
/// Suggestions added before the call to `.seal_suggestions()` will be preserved
/// and new suggestions will be ignored.
#[rustc_lint_diagnostics]
pub fn seal_suggestions(&mut self) -> &mut Self {
if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
@ -869,7 +845,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
///
/// A new suggestion is added if suggestions are enabled for this diagnostic.
/// Otherwise, they are ignored.
#[rustc_lint_diagnostics]
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions {
for part in &subst.parts {
@ -890,7 +865,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_multipart_suggestion,
/// Show a suggestion that has multiple parts to it.
/// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -907,7 +881,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Show a suggestion that has multiple parts to it, always as its own subdiagnostic.
/// In other words, multiple changes need to be applied as part of this suggestion.
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -923,7 +896,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
}
/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -966,7 +938,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability.
#[rustc_lint_diagnostics]
pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -999,7 +970,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// * may contain a name of a function, variable, or type, but not whole expressions
///
/// See [`CodeSuggestion`] for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion(
&mut self,
sp: Span,
@ -1018,7 +988,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
} }
/// [`Diag::span_suggestion()`] but you can set the [`SuggestionStyle`].
#[rustc_lint_diagnostics]
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
@ -1044,7 +1013,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestion_verbose,
/// Always show the suggested change.
#[rustc_lint_diagnostics]
pub fn span_suggestion_verbose(
&mut self,
sp: Span,
@ -1065,7 +1033,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span_suggestions,
/// Prints out a message with multiple suggested edits of the code.
/// See also [`Diag::span_suggestion()`].
#[rustc_lint_diagnostics]
pub fn span_suggestions(
&mut self,
sp: Span,
@ -1082,7 +1049,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
)
} }
#[rustc_lint_diagnostics]
pub fn span_suggestions_with_style(
&mut self,
sp: Span,
@ -1113,7 +1079,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// Prints out a message with multiple suggested edits of the code, where each edit consists of
/// multiple parts.
/// See also [`Diag::multipart_suggestion()`].
#[rustc_lint_diagnostics]
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagMessage>,
@ -1160,7 +1125,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// inline, it will only show the message and not the suggestion.
///
/// See [`CodeSuggestion`] for more information.
#[rustc_lint_diagnostics]
pub fn span_suggestion_short(
&mut self,
sp: Span,
@ -1184,7 +1148,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// be from the message, showing the span label inline would be visually unpleasant
/// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
/// improve understandability.
#[rustc_lint_diagnostics]
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
@ -1207,7 +1170,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
///
/// This is intended to be used for suggestions that are *very* obvious in what the changes
/// need to be from the message, but we still want other tools to be able to apply them.
#[rustc_lint_diagnostics]
pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
@ -1229,7 +1191,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
/// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
/// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
subdiagnostic.add_to_diag(self);
self
@ -1248,7 +1209,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
@ -1257,7 +1217,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage });
self
@ -1265,7 +1224,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_code,
/// Add an error code.
#[rustc_lint_diagnostics]
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
@ -1273,7 +1231,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_lint_id,
/// Add an argument.
#[rustc_lint_diagnostics]
pub fn lint_id(
&mut self,
id: LintExpectationId,
@ -1284,7 +1241,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_primary_message,
/// Add a primary message.
#[rustc_lint_diagnostics]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
@ -1292,7 +1248,6 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_arg,
/// Add an argument.
#[rustc_lint_diagnostics]
pub fn arg(
&mut self,
name: impl Into<DiagArgName>,

View file

@ -4,9 +4,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::direct_use_of_rustc_type_ir)]
#![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(bootstrap, feature(array_windows))]
#![feature(assert_matches)]
#![feature(associated_type_defaults)]
@ -23,7 +21,6 @@
extern crate self as rustc_errors;
use std::assert_matches::assert_matches;
use std::backtrace::{Backtrace, BacktraceStatus};
use std::borrow::Cow;
use std::cell::Cell;
@ -55,10 +52,10 @@ pub use diagnostic_impls::{
};
pub use emitter::ColorConfig;
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
use rustc_data_structures::AtomicRef;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{DynSend, Lock};
use rustc_data_structures::{AtomicRef, assert_matches};
pub use rustc_error_messages::{
DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
@ -1217,22 +1214,16 @@ impl<'a> DiagCtxtHandle<'a> {
// Functions beginning with `struct_`/`create_` create a diagnostic. Other
// functions create and emit a diagnostic all in one go.
impl<'a> DiagCtxtHandle<'a> {
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> Diag<'a, BugAbort> {
Diag::new(self, Bug, msg.into())
}
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit()
}
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn struct_span_bug(
self,
@ -1242,8 +1233,6 @@ impl<'a> DiagCtxtHandle<'a> {
self.struct_bug(msg).with_span(span)
}
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_span_bug(span, msg.into()).emit()
@ -1259,19 +1248,16 @@ impl<'a> DiagCtxtHandle<'a> {
self.create_bug(bug).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> Diag<'a, FatalAbort> {
Diag::new(self, Fatal, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_fatal(
self,
@ -1281,7 +1267,6 @@ impl<'a> DiagCtxtHandle<'a> {
self.struct_fatal(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
self.struct_span_fatal(span, msg).emit()
@ -1311,19 +1296,16 @@ impl<'a> DiagCtxtHandle<'a> {
}
// FIXME: This method should be removed (every error should have an associated error code).
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_err(self, msg: impl Into<DiagMessage>) -> Diag<'a> {
Diag::new(self, Error, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn err(self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_err(
self,
@ -1333,7 +1315,6 @@ impl<'a> DiagCtxtHandle<'a> {
self.struct_err(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
self,
@ -1354,9 +1335,6 @@ impl<'a> DiagCtxtHandle<'a> {
}
/// Ensures that an error is printed. See [`Level::DelayedBug`].
//
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> ErrorGuaranteed {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit()
@ -1366,9 +1344,6 @@ impl<'a> DiagCtxtHandle<'a> {
///
/// Note: this function used to be called `delay_span_bug`. It was renamed
/// to match similar functions like `span_err`, `span_warn`, etc.
//
// No `#[rustc_lint_diagnostics]` and no `impl Into<DiagMessage>` because bug messages aren't
// user-facing.
#[track_caller]
pub fn span_delayed_bug(
self,
@ -1378,19 +1353,16 @@ impl<'a> DiagCtxtHandle<'a> {
Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).with_span(sp).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Warning, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn warn(self, msg: impl Into<DiagMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_warn(
self,
@ -1400,7 +1372,6 @@ impl<'a> DiagCtxtHandle<'a> {
self.struct_warn(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_warn(span, msg).emit()
@ -1416,19 +1387,16 @@ impl<'a> DiagCtxtHandle<'a> {
self.create_warn(warning).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Note, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn note(&self, msg: impl Into<DiagMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_note(
self,
@ -1438,7 +1406,6 @@ impl<'a> DiagCtxtHandle<'a> {
self.struct_note(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_note(span, msg).emit()
@ -1454,25 +1421,21 @@ impl<'a> DiagCtxtHandle<'a> {
self.create_note(note).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_help(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Help, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, FailureNote, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> Diag<'a, ()> {
Diag::new(self, Allow, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> Diag<'a, ()> {
Diag::new(self, Expect, msg).with_lint_id(id)
@ -1745,7 +1708,7 @@ impl DiagCtxtInner {
message: DiagMessage,
args: impl Iterator<Item = DiagArg<'a>>,
) -> SubdiagMessage {
SubdiagMessage::Translated(Cow::from(self.eagerly_translate_to_string(message, args)))
SubdiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args)))
}
/// Translate `message` eagerly with `args` to `String`.

View file

@ -18,9 +18,14 @@ impl<'a> MdStream<'a> {
parse::entrypoint(s)
}
/// Write formatted output to an anstream buffer
pub fn write_anstream_buf(&self, buf: &mut Vec<u8>) -> io::Result<()> {
term::entrypoint(self, buf)
/// Write formatted output to a stdout buffer, optionally with
/// a formatter for code blocks
pub fn write_anstream_buf(
&self,
buf: &mut Vec<u8>,
formatter: Option<&(dyn Fn(&str, &mut Vec<u8>) -> io::Result<()> + 'static)>,
) -> io::Result<()> {
term::entrypoint(self, buf, formatter)
}
}

View file

@ -12,29 +12,33 @@ thread_local! {
static CURSOR: Cell<usize> = const { Cell::new(0) };
/// Width of the terminal
static WIDTH: Cell<usize> = const { Cell::new(DEFAULT_COLUMN_WIDTH) };
}
/// Print to terminal output to a buffer
pub(crate) fn entrypoint(stream: &MdStream<'_>, buf: &mut Vec<u8>) -> io::Result<()> {
#[cfg(not(test))]
if let Some((w, _)) = termize::dimensions() {
WIDTH.set(std::cmp::min(w, DEFAULT_COLUMN_WIDTH));
}
write_stream(stream, buf, None, 0)?;
/// Print to the terminal output to a buffer
/// optionally with a formatter for code blocks
pub(crate) fn entrypoint(
stream: &MdStream<'_>,
buf: &mut Vec<u8>,
formatter: Option<&(dyn Fn(&str, &mut Vec<u8>) -> io::Result<()> + 'static)>,
) -> io::Result<()> {
write_stream(stream, buf, None, 0, formatter)?;
buf.write_all(b"\n")
}
/// Write the buffer, reset to the default style after each
/// Write the buffer, reset to the default style after each,
/// optionally with a formatter for code blocks
fn write_stream(
MdStream(stream): &MdStream<'_>,
buf: &mut Vec<u8>,
default: Option<Style>,
indent: usize,
formatter: Option<&(dyn Fn(&str, &mut Vec<u8>) -> io::Result<()> + 'static)>,
) -> io::Result<()> {
for tt in stream {
write_tt(tt, buf, default, indent)?;
write_tt(tt, buf, default, indent, formatter)?;
}
reset_opt_style(buf, default)?;
Ok(())
}
@ -43,12 +47,17 @@ fn write_tt(
buf: &mut Vec<u8>,
default: Option<Style>,
indent: usize,
formatter: Option<&(dyn Fn(&str, &mut Vec<u8>) -> io::Result<()> + 'static)>,
) -> io::Result<()> {
match tt {
MdTree::CodeBlock { txt, lang: _ } => {
reset_opt_style(buf, default)?;
let style = Style::new().effects(Effects::DIMMED);
write!(buf, "{style}{txt}{style:#}")?;
if let Some(formatter) = formatter {
formatter(txt, buf)?;
} else {
let style = Style::new().effects(Effects::DIMMED);
write!(buf, "{style}{txt}{style:#}")?;
}
render_opt_style(buf, default)?;
}
MdTree::CodeInline(txt) => {
@ -105,7 +114,7 @@ fn write_tt(
};
reset_opt_style(buf, default)?;
write!(buf, "{cs}")?;
write_stream(stream, buf, Some(cs), 0)?;
write_stream(stream, buf, Some(cs), 0, None)?;
write!(buf, "{cs:#}")?;
render_opt_style(buf, default)?;
buf.write_all(b"\n")?;
@ -113,12 +122,12 @@ fn write_tt(
MdTree::OrderedListItem(n, stream) => {
let base = format!("{n}. ");
write_wrapping(buf, &format!("{base:<4}"), indent, None, None)?;
write_stream(stream, buf, None, indent + 4)?;
write_stream(stream, buf, None, indent + 4, None)?;
}
MdTree::UnorderedListItem(stream) => {
let base = "* ";
write_wrapping(buf, &format!("{base:<4}"), indent, None, None)?;
write_stream(stream, buf, None, indent + 4)?;
write_stream(stream, buf, None, indent + 4, None)?;
}
// Patterns popped in previous step
MdTree::Comment(_) | MdTree::LinkDef { .. } | MdTree::RefLink { .. } => unreachable!(),

View file

@ -1,13 +1,13 @@
H1 Heading ]8;;http://docs.rs\with a link]8;;\
H1 Heading ]8;;http://docs.rs\with a link]8;;\
H1 content: some words in bold and so does inline code
H2 Heading
H2 Heading
H2 content: some words in italic
H3 Heading
H3 Heading
H3 content: strikethrough text
H4 Heading
H4 Heading
H4 content: A ]8;;https://docs.rs\simple link]8;;\ and a ]8;;http://docs.rs\remote-link]8;;\.
--------------------------------------------------------------------------------------------------------------------------------------------
A section break was above. We can also do paragraph breaks:
@ -24,7 +24,7 @@ Or ordered:
elit quam, pulvinar ac risus in, dictum vehicula turpis. Vestibulum neque est, accumsan in cursus sit amet, dictum a nunc. Suspendisse
aliquet, lorem eu eleifend accumsan, magna neque sodales nisi, a aliquet lectus leo eu sem.
--------------------------------------------------------------------------------------------------------------------------------------------
Code
Code
Both inline code and code blocks are supported:
/// A rust enum

View file

@ -65,7 +65,7 @@ fn test_output() {
let bless = std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
let ast = MdStream::parse_str(INPUT);
let mut buffer = Vec::new();
ast.write_anstream_buf(&mut buffer).unwrap();
ast.write_anstream_buf(&mut buffer, None).unwrap();
let mut blessed = PathBuf::new();
blessed.extend(OUTPUT_PATH);

View file

@ -76,7 +76,7 @@ impl Translator {
) -> Result<Cow<'a, str>, TranslateError<'a>> {
trace!(?message, ?args);
let (identifier, attr) = match message {
DiagMessage::Str(msg) | DiagMessage::Translated(msg) => {
DiagMessage::Str(msg) => {
return Ok(Cow::Borrowed(msg));
}
DiagMessage::FluentIdentifier(identifier, attr) => (identifier, attr),

View file

@ -21,6 +21,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_parse = { path = "../rustc_parse" }
# We must use the proc_macro version that we will compile proc-macros against,
# not the one from our own sysroot.
@ -28,6 +29,7 @@ rustc_proc_macro = { path = "../rustc_proc_macro" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
scoped-tls = "1.0"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1"

View file

@ -1173,6 +1173,10 @@ pub trait ResolverExpand {
/// Record the name of an opaque `Ty::ImplTrait` pre-expansion so that it can be used
/// to generate an item name later that does not reference placeholder macros.
fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol);
/// Mark the scope as having a compile error so that error for lookup in this scope
/// should be suppressed
fn mark_scope_with_compile_error(&mut self, parent_node: NodeId);
}
pub trait LintStoreExpand {
@ -1351,8 +1355,6 @@ impl<'a> ExtCtxt<'a> {
for (span, notes) in self.expansions.iter() {
let mut db = self.dcx().create_note(errors::TraceMacro { span: *span });
for note in notes {
// FIXME: make this translatable
#[allow(rustc::untranslatable_diagnostic)]
db.note(note.clone());
}
db.emit();

View file

@ -19,6 +19,7 @@ use rustc_feature::{
ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES,
UNSTABLE_LANG_FEATURES,
};
use rustc_hir::Target;
use rustc_session::Session;
use rustc_session::parse::feature_err;
use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
@ -403,6 +404,8 @@ impl<'a> StripUnconfigured<'a> {
attr,
attr.span,
self.lint_node_id,
// Doesn't matter what the target actually is here.
Target::Crate,
self.features,
emit_errors,
parse_cfg,

View file

@ -999,7 +999,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
})
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
let kind = match item {
Annotatable::Item(_)
@ -2218,6 +2217,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
&attr,
attr.span,
self.cfg().lint_node_id,
// Target doesn't matter for `cfg` parsing.
Target::Crate,
self.cfg().features,
ShouldEmit::ErrorsAndLints,
parse_cfg,

View file

@ -1,6 +1,5 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![cfg_attr(bootstrap, feature(array_windows))]
#![feature(associated_type_defaults)]
#![feature(if_let_guard)]
@ -13,8 +12,6 @@
mod build;
mod errors;
// FIXME(Nilstrieb) Translate macro_rules diagnostics
#[allow(rustc::untranslatable_diagnostic)]
mod mbe;
mod placeholders;
mod proc_macro_server;
@ -25,8 +22,10 @@ pub mod base;
pub mod config;
pub mod expand;
pub mod module;
// FIXME(Nilstrieb) Translate proc_macro diagnostics
#[allow(rustc::untranslatable_diagnostic)]
pub mod proc_macro;
pub fn provide(providers: &mut rustc_middle::query::Providers) {
providers.derive_macro_expansion = proc_macro::provide_derive_macro_expansion;
}
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -1,9 +1,11 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::ErrorGuaranteed;
use rustc_middle::ty::{self, TyCtxt};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::Session;
use rustc_session::config::ProcMacroExecutionStrategy;
use rustc_span::Span;
use rustc_span::profiling::SpannedEventArgRecorder;
use rustc_span::{LocalExpnId, Span};
use {rustc_ast as ast, rustc_proc_macro as pm};
use crate::base::{self, *};
@ -30,9 +32,9 @@ impl<T> pm::bridge::server::MessagePipe<T> for MessagePipe<T> {
}
}
fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy + 'static {
fn exec_strategy(sess: &Session) -> impl pm::bridge::server::ExecutionStrategy + 'static {
pm::bridge::server::MaybeCrossThread::<MessagePipe<_>>::new(
ecx.sess.opts.unstable_opts.proc_macro_execution_strategy
sess.opts.unstable_opts.proc_macro_execution_strategy
== ProcMacroExecutionStrategy::CrossThread,
)
}
@ -54,7 +56,7 @@ impl base::BangProcMacro for BangProcMacro {
});
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let strategy = exec_strategy(ecx.sess);
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
ecx.dcx().emit_err(errors::ProcMacroPanicked {
@ -85,7 +87,7 @@ impl base::AttrProcMacro for AttrProcMacro {
});
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let strategy = exec_strategy(ecx.sess);
let server = proc_macro_server::Rustc::new(ecx);
self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err(
|e| {
@ -101,7 +103,7 @@ impl base::AttrProcMacro for AttrProcMacro {
}
pub struct DeriveProcMacro {
pub client: pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>,
pub client: DeriveClient,
}
impl MultiItemModifier for DeriveProcMacro {
@ -113,6 +115,13 @@ impl MultiItemModifier for DeriveProcMacro {
item: Annotatable,
_is_derive_const: bool,
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let _timer = ecx.sess.prof.generic_activity_with_arg_recorder(
"expand_derive_proc_macro_outer",
|recorder| {
recorder.record_arg_with_span(ecx.sess.source_map(), ecx.expansion_descr(), span);
},
);
// We need special handling for statement items
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
let is_stmt = matches!(item, Annotatable::Stmt(..));
@ -123,36 +132,31 @@ impl MultiItemModifier for DeriveProcMacro {
// altogether. See #73345.
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
let input = item.to_tokens();
let stream = {
let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
recorder.record_arg_with_span(
ecx.sess.source_map(),
ecx.expansion_descr(),
span,
);
});
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx);
let server = proc_macro_server::Rustc::new(ecx);
match self.client.run(&strategy, server, input, proc_macro_backtrace) {
Ok(stream) => stream,
Err(e) => {
ecx.dcx().emit_err({
errors::ProcMacroDerivePanicked {
span,
message: e.as_str().map(|message| {
errors::ProcMacroDerivePanickedHelp { message: message.into() }
}),
}
});
return ExpandResult::Ready(vec![]);
}
}
let invoc_id = ecx.current_expansion.id;
let res = if ecx.sess.opts.incremental.is_some()
&& ecx.sess.opts.unstable_opts.cache_proc_macros
{
ty::tls::with(|tcx| {
let input = &*tcx.arena.alloc(input);
let key: (LocalExpnId, &TokenStream) = (invoc_id, input);
QueryDeriveExpandCtx::enter(ecx, self.client, move || {
tcx.derive_macro_expansion(key).cloned()
})
})
} else {
expand_derive_macro(invoc_id, input, ecx, self.client)
};
let Ok(output) = res else {
// error will already have been emitted
return ExpandResult::Ready(vec![]);
};
let error_count_before = ecx.dcx().err_count();
let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive"));
let mut parser = Parser::new(&ecx.sess.psess, output, Some("proc-macro derive"));
let mut items = vec![];
loop {
@ -180,3 +184,101 @@ impl MultiItemModifier for DeriveProcMacro {
ExpandResult::Ready(items)
}
}
/// Provide a query for computing the output of a derive macro.
pub(super) fn provide_derive_macro_expansion<'tcx>(
tcx: TyCtxt<'tcx>,
key: (LocalExpnId, &'tcx TokenStream),
) -> Result<&'tcx TokenStream, ()> {
let (invoc_id, input) = key;
// Make sure that we invalidate the query when the crate defining the proc macro changes
let _ = tcx.crate_hash(invoc_id.expn_data().macro_def_id.unwrap().krate);
QueryDeriveExpandCtx::with(|ecx, client| {
expand_derive_macro(invoc_id, input.clone(), ecx, client).map(|ts| &*tcx.arena.alloc(ts))
})
}
type DeriveClient = pm::bridge::client::Client<pm::TokenStream, pm::TokenStream>;
fn expand_derive_macro(
invoc_id: LocalExpnId,
input: TokenStream,
ecx: &mut ExtCtxt<'_>,
client: DeriveClient,
) -> Result<TokenStream, ()> {
let _timer =
ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| {
let invoc_expn_data = invoc_id.expn_data();
let span = invoc_expn_data.call_site;
let event_arg = invoc_expn_data.kind.descr();
recorder.record_arg_with_span(ecx.sess.source_map(), event_arg.clone(), span);
});
let proc_macro_backtrace = ecx.ecfg.proc_macro_backtrace;
let strategy = exec_strategy(ecx.sess);
let server = proc_macro_server::Rustc::new(ecx);
match client.run(&strategy, server, input, proc_macro_backtrace) {
Ok(stream) => Ok(stream),
Err(e) => {
let invoc_expn_data = invoc_id.expn_data();
let span = invoc_expn_data.call_site;
ecx.dcx().emit_err({
errors::ProcMacroDerivePanicked {
span,
message: e.as_str().map(|message| errors::ProcMacroDerivePanickedHelp {
message: message.into(),
}),
}
});
Err(())
}
}
}
/// Stores the context necessary to expand a derive proc macro via a query.
struct QueryDeriveExpandCtx {
/// Type-erased version of `&mut ExtCtxt`
expansion_ctx: *mut (),
client: DeriveClient,
}
impl QueryDeriveExpandCtx {
/// Store the extension context and the client into the thread local value.
/// It will be accessible via the `with` method while `f` is active.
fn enter<F, R>(ecx: &mut ExtCtxt<'_>, client: DeriveClient, f: F) -> R
where
F: FnOnce() -> R,
{
// We need erasure to get rid of the lifetime
let ctx = Self { expansion_ctx: ecx as *mut _ as *mut (), client };
DERIVE_EXPAND_CTX.set(&ctx, || f())
}
/// Accesses the thread local value of the derive expansion context.
/// Must be called while the `enter` function is active.
fn with<F, R>(f: F) -> R
where
F: for<'a, 'b> FnOnce(&'b mut ExtCtxt<'a>, DeriveClient) -> R,
{
DERIVE_EXPAND_CTX.with(|ctx| {
let ectx = {
let casted = ctx.expansion_ctx.cast::<ExtCtxt<'_>>();
// SAFETY: We can only get the value from `with` while the `enter` function
// is active (on the callstack), and that function's signature ensures that the
// lifetime is valid.
// If `with` is called at some other time, it will panic due to usage of
// `scoped_tls::with`.
unsafe { casted.as_mut().unwrap() }
};
f(ectx, ctx.client)
})
}
}
// When we invoke a query to expand a derive proc macro, we need to provide it with the expansion
// context and derive Client. We do that using a thread-local.
scoped_tls::scoped_thread_local!(static DERIVE_EXPAND_CTX: QueryDeriveExpandCtx);

View file

@ -548,9 +548,6 @@ impl server::FreeFunctions for Rustc<'_, '_> {
Diag::new(self.psess().dcx(), diagnostic.level.to_internal(), message);
diag.span(MultiSpan::from_spans(diagnostic.spans));
for child in diagnostic.children {
// This message comes from another diagnostic, and we are just reconstructing the
// diagnostic, so there's no need for translation.
#[allow(rustc::untranslatable_diagnostic)]
diag.sub(child.level.to_internal(), child.message, MultiSpan::from_spans(child.spans));
}
diag.emit();

View file

@ -678,7 +678,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No,
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic abis."
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
),
// Limits:
@ -1182,12 +1182,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_lint_untracked_query_information, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
// APIs. Any function with this attribute will be checked by that lint.
rustc_attr!(
rustc_lint_diagnostics, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future).
rustc_attr!(
@ -1275,38 +1269,38 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"
),
rustc_attr!(
rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts."
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"
),
rustc_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"
),
rustc_attr!(
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument."
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"
),
rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"
),
rustc_attr!(
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"
),
rustc_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"
),
rustc_attr!(
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
@ -1333,7 +1327,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
),
BuiltinAttribute {
@ -1396,7 +1390,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
EncodeCrossCrate::No,
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is of the following type, for compatibility in \
editions < 2021 (array) or editions < 2024 (boxed_slice)."
editions < 2021 (array) or editions < 2024 (boxed_slice)"
),
rustc_attr!(
rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]),

Some files were not shown because too many files have changed in this diff Show more