Skip to content

Rollup of 5 pull requests #94935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Mar 15, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
@@ -188,8 +188,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
("x86", "avx512gfni") => smallvec!["gfni"],
("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
("aarch64", "fp") => smallvec!["fp-armv8"],
("aarch64", "fp16") => smallvec!["fullfp16"],
("aarch64", "fhm") => smallvec!["fp16fml"],
("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
("aarch64", "dpb") => smallvec!["ccpp"],
("aarch64", "dpb2") => smallvec!["ccdp"],
@@ -198,6 +196,19 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]
("aarch64", "pmuv3") => smallvec!["perfmon"],
("aarch64", "paca") => smallvec!["pauth"],
("aarch64", "pacg") => smallvec!["pauth"],
// Rust ties fp and neon together. In LLVM neon implicitly enables fp,
// but we manually enable neon when a feature only implicitly enables fp
("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
("aarch64", "sve") => smallvec!["sve", "neon"],
("aarch64", "sve2") => smallvec!["sve2", "neon"],
("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
(_, s) => smallvec![s],
}
}
@@ -490,7 +501,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
return SmallVec::<[_; 2]>::new();
}
// ... otherwise though we run through `to_llvm_feature when
// ... otherwise though we run through `to_llvm_features` when
// passing requests down to LLVM. This means that all in-language
// features also work on the command line instead of having two
// different names when the LLVM name and the Rust name differ.
109 changes: 56 additions & 53 deletions compiler/rustc_codegen_ssa/src/target_features.rs
Original file line number Diff line number Diff line change
@@ -44,105 +44,108 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[

const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// FEAT_AdvSimd
("neon", Some(sym::aarch64_target_feature)),
("neon", None),
// FEAT_FP
("fp", Some(sym::aarch64_target_feature)),
("fp", None),
// FEAT_FP16
("fp16", Some(sym::aarch64_target_feature)),
("fp16", None),
// FEAT_SVE
("sve", Some(sym::aarch64_target_feature)),
("sve", None),
// FEAT_CRC
("crc", Some(sym::aarch64_target_feature)),
("crc", None),
// FEAT_RAS
("ras", Some(sym::aarch64_target_feature)),
("ras", None),
// FEAT_LSE
("lse", Some(sym::aarch64_target_feature)),
("lse", None),
// FEAT_RDM
("rdm", Some(sym::aarch64_target_feature)),
("rdm", None),
// FEAT_RCPC
("rcpc", Some(sym::aarch64_target_feature)),
("rcpc", None),
// FEAT_RCPC2
("rcpc2", Some(sym::aarch64_target_feature)),
("rcpc2", None),
// FEAT_DotProd
("dotprod", Some(sym::aarch64_target_feature)),
("dotprod", None),
// FEAT_TME
("tme", Some(sym::aarch64_target_feature)),
("tme", None),
// FEAT_FHM
("fhm", Some(sym::aarch64_target_feature)),
("fhm", None),
// FEAT_DIT
("dit", Some(sym::aarch64_target_feature)),
("dit", None),
// FEAT_FLAGM
("flagm", Some(sym::aarch64_target_feature)),
("flagm", None),
// FEAT_SSBS
("ssbs", Some(sym::aarch64_target_feature)),
("ssbs", None),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
("sb", None),
// FEAT_PAUTH (address authentication)
("paca", Some(sym::aarch64_target_feature)),
("paca", None),
// FEAT_PAUTH (generic authentication)
("pacg", Some(sym::aarch64_target_feature)),
("pacg", None),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
("dpb", None),
// FEAT_DPB2
("dpb2", Some(sym::aarch64_target_feature)),
("dpb2", None),
// FEAT_SVE2
("sve2", Some(sym::aarch64_target_feature)),
("sve2", None),
// FEAT_SVE2_AES
("sve2-aes", Some(sym::aarch64_target_feature)),
("sve2-aes", None),
// FEAT_SVE2_SM4
("sve2-sm4", Some(sym::aarch64_target_feature)),
("sve2-sm4", None),
// FEAT_SVE2_SHA3
("sve2-sha3", Some(sym::aarch64_target_feature)),
("sve2-sha3", None),
// FEAT_SVE2_BitPerm
("sve2-bitperm", Some(sym::aarch64_target_feature)),
("sve2-bitperm", None),
// FEAT_FRINTTS
("frintts", Some(sym::aarch64_target_feature)),
("frintts", None),
// FEAT_I8MM
("i8mm", Some(sym::aarch64_target_feature)),
("i8mm", None),
// FEAT_F32MM
("f32mm", Some(sym::aarch64_target_feature)),
("f32mm", None),
// FEAT_F64MM
("f64mm", Some(sym::aarch64_target_feature)),
("f64mm", None),
// FEAT_BF16
("bf16", Some(sym::aarch64_target_feature)),
("bf16", None),
// FEAT_RAND
("rand", Some(sym::aarch64_target_feature)),
("rand", None),
// FEAT_BTI
("bti", Some(sym::aarch64_target_feature)),
("bti", None),
// FEAT_MTE
("mte", Some(sym::aarch64_target_feature)),
("mte", None),
// FEAT_JSCVT
("jsconv", Some(sym::aarch64_target_feature)),
("jsconv", None),
// FEAT_FCMA
("fcma", Some(sym::aarch64_target_feature)),
("fcma", None),
// FEAT_AES
("aes", Some(sym::aarch64_target_feature)),
("aes", None),
// FEAT_SHA1 & FEAT_SHA256
("sha2", Some(sym::aarch64_target_feature)),
("sha2", None),
// FEAT_SHA512 & FEAT_SHA3
("sha3", Some(sym::aarch64_target_feature)),
("sha3", None),
// FEAT_SM3 & FEAT_SM4
("sm4", Some(sym::aarch64_target_feature)),
("sm4", None),
// FEAT_PAN
("pan", Some(sym::aarch64_target_feature)),
("pan", None),
// FEAT_LOR
("lor", Some(sym::aarch64_target_feature)),
("lor", None),
// FEAT_VHE
("vh", Some(sym::aarch64_target_feature)),
("vh", None),
// FEAT_PMUv3
("pmuv3", Some(sym::aarch64_target_feature)),
("pmuv3", None),
// FEAT_SPE
("spe", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
("v8.4a", Some(sym::aarch64_target_feature)),
("v8.5a", Some(sym::aarch64_target_feature)),
("v8.6a", Some(sym::aarch64_target_feature)),
("v8.7a", Some(sym::aarch64_target_feature)),
("spe", None),
("v8.1a", Some(sym::aarch64_ver_target_feature)),
("v8.2a", Some(sym::aarch64_ver_target_feature)),
("v8.3a", Some(sym::aarch64_ver_target_feature)),
("v8.4a", Some(sym::aarch64_ver_target_feature)),
("v8.5a", Some(sym::aarch64_ver_target_feature)),
("v8.6a", Some(sym::aarch64_ver_target_feature)),
("v8.7a", Some(sym::aarch64_ver_target_feature)),
];

const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
const AARCH64_TIED_FEATURES: &[&[&str]] = &[
&["fp", "neon"], // Silicon always has both, so avoid needless complications
&["paca", "pacg"], // Together these represent `pauth` in LLVM
];

const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("adx", Some(sym::adx_target_feature)),
25 changes: 24 additions & 1 deletion compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@ use crate::Substitution;
use crate::SubstitutionPart;
use crate::SuggestionStyle;
use crate::ToolMetadata;
use rustc_lint_defs::Applicability;
use rustc_data_structures::stable_map::FxHashMap;
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_serialize::json::Json;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
@@ -138,6 +139,28 @@ impl Diagnostic {
}
}

pub fn update_unstable_expectation_id(
&mut self,
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
) {
if let Level::Expect(expectation_id) = &mut self.level {
if expectation_id.is_stable() {
return;
}

// The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
// The lint index inside the attribute is manually transferred here.
let lint_index = expectation_id.get_lint_index();
expectation_id.set_lint_index(None);
let mut stable_id = *unstable_to_stable
.get(&expectation_id)
.expect("each unstable `LintExpectationId` must have a matching stable id");

stable_id.set_lint_index(lint_index);
*expectation_id = stable_id;
}
}

pub fn has_future_breakage(&self) -> bool {
match self.code {
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
30 changes: 18 additions & 12 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -522,6 +522,11 @@ impl Drop for HandlerInner {
"no warnings or errors encountered even though `delayed_good_path_bugs` issued",
);
}

assert!(
self.unstable_expect_diagnostics.is_empty(),
"all diagnostics with unstable expectations should have been converted",
);
}
}

@@ -942,29 +947,30 @@ impl Handler {

let mut inner = self.inner.borrow_mut();
for mut diag in diags.into_iter() {
let mut unstable_id = diag
diag.update_unstable_expectation_id(unstable_to_stable);

let stable_id = diag
.level
.get_expectation_id()
.expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");

// The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
// The lint index inside the attribute is manually transferred here.
let lint_index = unstable_id.get_lint_index();
unstable_id.set_lint_index(None);
let mut stable_id = *unstable_to_stable
.get(&unstable_id)
.expect("each unstable `LintExpectationId` must have a matching stable id");

stable_id.set_lint_index(lint_index);
diag.level = Level::Expect(stable_id);
inner.fulfilled_expectations.insert(stable_id);

(*TRACK_DIAGNOSTICS)(&diag);
}

inner
.stashed_diagnostics
.values_mut()
.for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
inner
.future_breakage_diagnostics
.iter_mut()
.for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
}

/// This methods steals all [`LintExpectationId`]s that are stored inside
/// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
#[must_use]
pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
assert!(
self.inner.borrow().unstable_expect_diagnostics.is_empty(),
8 changes: 6 additions & 2 deletions compiler/rustc_expand/src/mbe/macro_check.rs
Original file line number Diff line number Diff line change
@@ -337,8 +337,12 @@ fn check_occurrences(
let name = MacroRulesNormalizedIdent::new(name);
check_ops_is_prefix(sess, node_id, macros, binders, ops, span, name);
}
// FIXME(c410-f3r) Check token (https://github.com/rust-lang/rust/issues/93902)
TokenTree::MetaVarExpr(..) => {}
TokenTree::MetaVarExpr(dl, ref mve) => {
let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else {
return;
};
check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name);
}
TokenTree::Delimited(_, ref del) => {
check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
}
7 changes: 5 additions & 2 deletions compiler/rustc_expand/src/mbe/macro_parser.rs
Original file line number Diff line number Diff line change
@@ -324,8 +324,11 @@ pub(super) fn count_names(ms: &[TokenTree]) -> usize {
TokenTree::Delimited(_, ref delim) => count_names(&delim.tts),
TokenTree::MetaVar(..) => 0,
TokenTree::MetaVarDecl(..) => 1,
// FIXME(c410-f3r) MetaVarExpr should be handled instead of being ignored
// https://github.com/rust-lang/rust/issues/9390
// Panicking here would abort execution because `parse_tree` makes use of this
// function. In other words, RHS meta-variable expressions eventually end-up here.
//
// `0` is still returned to inform that no meta-variable was found. `Meta-variables
// != Meta-variable expressions`
TokenTree::MetaVarExpr(..) => 0,
TokenTree::Sequence(_, ref seq) => seq.num_captures,
TokenTree::Token(..) => 0,
6 changes: 3 additions & 3 deletions compiler/rustc_expand/src/mbe/metavar_expr.rs
Original file line number Diff line number Diff line change
@@ -62,9 +62,9 @@ impl MetaVarExpr {
Ok(rslt)
}

crate fn ident(&self) -> Option<&Ident> {
match self {
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(&ident),
crate fn ident(&self) -> Option<Ident> {
match *self {
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_expand/src/mbe/transcribe.rs
Original file line number Diff line number Diff line change
@@ -399,7 +399,7 @@ fn lockstep_iter_size(
TokenTree::MetaVarExpr(_, ref expr) => {
let default_rslt = LockstepIterSize::Unconstrained;
let Some(ident) = expr.ident() else { return default_rslt; };
let name = MacroRulesNormalizedIdent::new(ident.clone());
let name = MacroRulesNormalizedIdent::new(ident);
match lookup_cur_matched(name, interpolations, repeats) {
Some(MatchedSeq(ref ads)) => {
default_rslt.with(LockstepIterSize::Constraint(ads.len(), name))
@@ -479,7 +479,7 @@ fn count_repetitions<'a>(
count(cx, 0, depth_opt, matched, sp)
}

/// Returns a `NamedMatch` item declared on the RHS given an arbitrary [Ident]
/// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
fn matched_from_ident<'ctx, 'interp, 'rslt>(
cx: &ExtCtxt<'ctx>,
ident: Ident,
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
@@ -46,6 +46,8 @@ declare_features! (
// feature-group-start: accepted features
// -------------------------------------------------------------------------

/// Allows `#[target_feature(...)]` on aarch64 platforms
(accepted, aarch64_target_feature, "1.61.0", Some(44839), None),
/// Allows the sysV64 ABI to be specified on all platforms
/// instead of just the platforms on which it is the C ABI.
(accepted, abi_sysv64, "1.24.0", Some(36167), None),
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
@@ -243,7 +243,7 @@ declare_features! (
// FIXME: Document these and merge with the list below.

// Unstable `#[target_feature]` directives.
(active, aarch64_target_feature, "1.27.0", Some(44839), None),
(active, aarch64_ver_target_feature, "1.27.0", Some(44839), None),
(active, adx_target_feature, "1.32.0", Some(44839), None),
(active, arm_target_feature, "1.27.0", Some(44839), None),
(active, avx512_target_feature, "1.27.0", Some(44839), None),
9 changes: 5 additions & 4 deletions compiler/rustc_lint/src/expect.rs
Original file line number Diff line number Diff line change
@@ -30,10 +30,6 @@ fn emit_unfulfilled_expectation_lint(
hir_id: HirId,
expectation: &LintExpectation,
) {
// FIXME: The current implementation doesn't cover cases where the
// `unfulfilled_lint_expectations` is actually expected by another lint
// expectation. This can be added here by checking the lint level and
// retrieving the `LintExpectationId` if it was expected.
tcx.struct_span_lint_hir(
builtin::UNFULFILLED_LINT_EXPECTATIONS,
hir_id,
@@ -43,6 +39,11 @@ fn emit_unfulfilled_expectation_lint(
if let Some(rationale) = expectation.reason {
diag.note(&rationale.as_str());
}

if expectation.is_unfulfilled_lint_expectations {
diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message");
}

diag.emit();
},
);
36 changes: 28 additions & 8 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ use rustc_middle::lint::{
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::{
builtin::{self, FORBIDDEN_LINT_GROUPS},
builtin::{self, FORBIDDEN_LINT_GROUPS, UNFULFILLED_LINT_EXPECTATIONS},
Level, Lint, LintExpectationId, LintId,
};
use rustc_session::parse::{add_feature_diagnostics, feature_err};
@@ -218,6 +218,14 @@ impl<'s> LintLevelsBuilder<'s> {
}
}
}

// The lint `unfulfilled_lint_expectations` can't be expected, as it would suppress itself.
// Handling expectations of this lint would add additional complexity with little to no
// benefit. The expect level for this lint will therefore be ignored.
if let Level::Expect(_) = level && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) {
return;
}

if let Level::ForceWarn = old_level {
self.current_specs_mut().insert(id, (old_level, old_src));
} else {
@@ -350,6 +358,22 @@ impl<'s> LintLevelsBuilder<'s> {
self.store.check_lint_name(&name, tool_name, self.registered_tools);
match &lint_result {
CheckLintNameResult::Ok(ids) => {
// This checks for instances where the user writes `#[expect(unfulfilled_lint_expectations)]`
// in that case we want to avoid overriding the lint level but instead add an expectation that
// can't be fulfilled. The lint message will include an explanation, that the
// `unfulfilled_lint_expectations` lint can't be expected.
if let Level::Expect(expect_id) = level {
// The `unfulfilled_lint_expectations` lint is not part of any lint groups. Therefore. we
// only need to check the slice if it contains a single lint.
let is_unfulfilled_lint_expectations = match ids {
[lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
_ => false,
};
self.lint_expectations.push((
expect_id,
LintExpectation::new(reason, sp, is_unfulfilled_lint_expectations),
));
}
let src = LintLevelSource::Node(
meta_item.path.segments.last().expect("empty lint name").ident.name,
sp,
@@ -360,10 +384,6 @@ impl<'s> LintLevelsBuilder<'s> {
self.insert_spec(id, (level, src));
}
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp)));
}
}

CheckLintNameResult::Tool(result) => {
@@ -381,7 +401,7 @@ impl<'s> LintLevelsBuilder<'s> {
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp)));
.push((expect_id, LintExpectation::new(reason, sp, false)));
}
}
Err((Some(ids), ref new_lint_name)) => {
@@ -425,7 +445,7 @@ impl<'s> LintLevelsBuilder<'s> {
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp)));
.push((expect_id, LintExpectation::new(reason, sp, false)));
}
}
Err((None, _)) => {
@@ -531,7 +551,7 @@ impl<'s> LintLevelsBuilder<'s> {
}
if let Level::Expect(expect_id) = level {
self.lint_expectations
.push((expect_id, LintExpectation::new(reason, sp)));
.push((expect_id, LintExpectation::new(reason, sp, false)));
}
} else {
panic!("renamed lint does not exist: {}", new_name);
8 changes: 5 additions & 3 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ pub enum Applicability {
/// Expected `Diagnostic`s get the lint level `Expect` which stores the `LintExpectationId`
/// to match it with the actual expectation later on.
///
/// The `LintExpectationId` has to be has stable between compilations, as diagnostic
/// The `LintExpectationId` has to be stable between compilations, as diagnostic
/// instances might be loaded from cache. Lint messages can be emitted during an
/// `EarlyLintPass` operating on the AST and during a `LateLintPass` traversing the
/// HIR tree. The AST doesn't have enough information to create a stable id. The
@@ -71,7 +71,7 @@ pub enum Applicability {
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash, Encodable, Decodable)]
pub enum LintExpectationId {
/// Used for lints emitted during the `EarlyLintPass`. This id is not
/// has stable and should not be cached.
/// hash stable and should not be cached.
Unstable { attr_id: AttrId, lint_index: Option<u16> },
/// The [`HirId`] that the lint expectation is attached to. This id is
/// stable and can be cached. The additional index ensures that nodes with
@@ -113,7 +113,9 @@ impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
lint_index.hash_stable(hcx, hasher);
}
_ => {
unreachable!("HashStable should only be called for a filled `LintExpectationId`")
unreachable!(
"HashStable should only be called for filled and stable `LintExpectationId`"
)
}
}
}
12 changes: 10 additions & 2 deletions compiler/rustc_middle/src/lint.rs
Original file line number Diff line number Diff line change
@@ -204,11 +204,19 @@ pub struct LintExpectation {
pub reason: Option<Symbol>,
/// The [`Span`] of the attribute that this expectation originated from.
pub emission_span: Span,
/// Lint messages for the `unfulfilled_lint_expectations` lint will be
/// adjusted to include an additional note. Therefore, we have to track if
/// the expectation is for the lint.
pub is_unfulfilled_lint_expectations: bool,
}

impl LintExpectation {
pub fn new(reason: Option<Symbol>, attr_span: Span) -> Self {
Self { reason, emission_span: attr_span }
pub fn new(
reason: Option<Symbol>,
emission_span: Span,
is_unfulfilled_lint_expectations: bool,
) -> Self {
Self { reason, emission_span, is_unfulfilled_lint_expectations }
}
}

23 changes: 13 additions & 10 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -2252,12 +2252,13 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Returns the type of metadata for (potentially fat) pointers to this type.
/// Returns the type of metadata for (potentially fat) pointers to this type,
/// and a boolean signifying if this is conditional on this type being `Sized`.
pub fn ptr_metadata_ty(
self,
tcx: TyCtxt<'tcx>,
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
) -> Ty<'tcx> {
) -> (Ty<'tcx>, bool) {
let tail = tcx.struct_tail_with_normalize(self, normalize);
match tail.kind() {
// Sized types
@@ -2277,28 +2278,30 @@ impl<'tcx> Ty<'tcx> {
| ty::Closure(..)
| ty::Never
| ty::Error(_)
// Extern types have metadata = ().
| ty::Foreign(..)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
// If returned by `struct_tail_without_normalization` this is the empty tuple,
// a.k.a. unit type, which is Sized
| ty::Tuple(..) => tcx.types.unit,
| ty::Tuple(..) => (tcx.types.unit, false),

ty::Str | ty::Slice(_) => tcx.types.usize,
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
ty::Dynamic(..) => {
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
(tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
},

ty::Projection(_)
| ty::Param(_)
| ty::Opaque(..)
| ty::Infer(ty::TyVar(_))
// type parameters only have unit metadata if they're sized, so return true
// to make sure we double check this during confirmation
ty::Param(_) | ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true),

ty::Infer(ty::TyVar(_))
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
}
}
}
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -278,6 +278,7 @@ symbols! {
_task_context,
a32,
aarch64_target_feature,
aarch64_ver_target_feature,
abi,
abi_amdgpu_kernel,
abi_avr_interrupt,
35 changes: 30 additions & 5 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -1469,6 +1469,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());

let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
// We throw away any obligations we get from this, since we normalize
// and confirm these obligations once again during confirmation
normalize_with_depth(
selcx,
obligation.param_env,
@@ -1485,7 +1487,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Foreign(_)
| ty::Str
| ty::Array(..)
| ty::Slice(_)
@@ -1498,6 +1499,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Never
// Extern types have unit metadata, according to RFC 2850
| ty::Foreign(_)
// If returned by `struct_tail_without_normalization` this is a unit struct
// without any fields, or not a struct, and therefore is Sized.
| ty::Adt(..)
@@ -1506,9 +1509,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// Integers and floats are always Sized, and so have unit type metadata.
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,

ty::Projection(..)
// type parameters, opaques, and unnormalized projections have pointer
// metadata if they're known (e.g. by the param_env) to be sized
ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
if tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env) =>
{
true
}

// FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
ty::Param(_)
| ty::Projection(..)
| ty::Opaque(..)
| ty::Param(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..)
@@ -1517,7 +1529,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
candidate_set.mark_ambiguous();
}
false
},
}
}
}
super::ImplSource::Param(..) => {
@@ -1727,7 +1739,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());

let mut obligations = vec![];
let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
normalize_with_depth_to(
selcx,
obligation.param_env,
@@ -1737,6 +1749,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
&mut obligations,
)
});
if check_is_sized {
let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
tcx.require_lang_item(LangItem::Sized, None),
tcx.mk_substs_trait(self_ty, &[]),
))
.without_const()
.to_predicate(tcx);
obligations.push(Obligation::new(
obligation.cause.clone(),
obligation.param_env,
sized_predicate,
));
}

let substs = tcx.mk_substs([self_ty.into()].iter());
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
@@ -2680,7 +2680,6 @@ fn from_target_feature(
// Only allow features whose feature gates have been enabled.
let allowed = match feature_gate.as_ref().copied() {
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature,
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
@@ -2696,6 +2695,7 @@ fn from_target_feature(
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
2 changes: 1 addition & 1 deletion library/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -206,7 +206,7 @@
#![feature(asm_const)]
//
// Target features:
#![feature(aarch64_target_feature)]
#![cfg_attr(bootstrap, feature(aarch64_target_feature))]
#![feature(adx_target_feature)]
#![feature(arm_target_feature)]
#![feature(avx512_target_feature)]
2 changes: 1 addition & 1 deletion src/test/run-make-fulldeps/simd-ffi/Makefile
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ define MK_TARGETS
# now.
$(1): simd.rs
$$(RUSTC) --target=$(1) --emit=llvm-ir,asm simd.rs \
-C target-feature='+neon,+sse2' -C extra-filename=-$(1)
-C target-feature='+fp,+neon,+sse2' -C extra-filename=-$(1)
endef

$(foreach targetxxx,$(TARGETS),$(eval $(call MK_TARGETS,$(targetxxx))))
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// check-pass
// ignore-tidy-linelength

#![feature(lint_reasons)]
#![warn(unused_mut)]

#![expect(unfulfilled_lint_expectations, reason = "idk why you would expect this")]
//~^ WARNING this lint expectation is unfulfilled
//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
//~| NOTE idk why you would expect this
//~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message

#[expect(unfulfilled_lint_expectations, reason = "a local: idk why you would expect this")]
//~^ WARNING this lint expectation is unfulfilled
//~| NOTE a local: idk why you would expect this
//~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
pub fn normal_test_fn() {
#[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
//~^ WARNING this lint expectation is unfulfilled
//~| NOTE this expectation will create a diagnostic with the default lint level
let mut v = vec![1, 1, 2, 3, 5];
v.sort();

// Check that lint lists including `unfulfilled_lint_expectations` are also handled correctly
#[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
//~^ WARNING this lint expectation is unfulfilled
//~| NOTE the expectation for `unused` should be fulfilled
//~| NOTE the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
let value = "I'm unused";
}

#[expect(warnings, reason = "this suppresses all warnings and also suppresses itself. No warning will be issued")]
pub fn expect_warnings() {
// This lint trigger will be suppressed
#[warn(unused_mut)]
let mut v = vec![1, 1, 2, 3, 5];
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
warning: this lint expectation is unfulfilled
--> $DIR/expect_unfulfilled_expectation.rs:7:11
|
LL | #![expect(unfulfilled_lint_expectations, reason = "idk why you would expect this")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
= note: idk why you would expect this
= note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message

warning: this lint expectation is unfulfilled
--> $DIR/expect_unfulfilled_expectation.rs:13:10
|
LL | #[expect(unfulfilled_lint_expectations, reason = "a local: idk why you would expect this")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: a local: idk why you would expect this
= note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message

warning: this lint expectation is unfulfilled
--> $DIR/expect_unfulfilled_expectation.rs:18:14
|
LL | #[expect(unused_mut, reason = "this expectation will create a diagnostic with the default lint level")]
| ^^^^^^^^^^
|
= note: this expectation will create a diagnostic with the default lint level

warning: this lint expectation is unfulfilled
--> $DIR/expect_unfulfilled_expectation.rs:25:22
|
LL | #[expect(unused, unfulfilled_lint_expectations, reason = "the expectation for `unused` should be fulfilled")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the expectation for `unused` should be fulfilled
= note: the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message

warning: 4 warnings emitted

2 changes: 1 addition & 1 deletion src/test/ui/target-feature/gate.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
// gate-test-avx512_target_feature
// gate-test-tbm_target_feature
// gate-test-arm_target_feature
// gate-test-aarch64_target_feature
// gate-test-hexagon_target_feature
// gate-test-mips_target_feature
// gate-test-wasm_target_feature
@@ -28,6 +27,7 @@
// gate-test-riscv_target_feature
// gate-test-ermsb_target_feature
// gate-test-bpf_target_feature
// gate-test-aarch64_ver_target_feature

#[target_feature(enable = "avx512bw")]
//~^ ERROR: currently unstable
2 changes: 1 addition & 1 deletion src/test/ui/target-feature/tied-features.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// build-fail
// compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
#![feature(aarch64_target_feature, target_feature_11)]
#![cfg_attr(bootstrap, feature(aarch64_target_feature))]
#![feature(no_core, lang_items)]
#![no_core]

22 changes: 22 additions & 0 deletions src/test/ui/traits/pointee-tail-is-generic-errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// edition:2018

#![feature(ptr_metadata)]
#![feature(type_alias_impl_trait)]

type Opaque = impl std::fmt::Debug + ?Sized;

fn opaque() -> &'static Opaque {
&[1] as &[i32]
}

fn a<T: ?Sized>() {
is_thin::<T>();
//~^ ERROR type mismatch resolving `<T as Pointee>::Metadata == ()`

is_thin::<Opaque>();
//~^ ERROR type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
}

fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}

fn main() {}
40 changes: 40 additions & 0 deletions src/test/ui/traits/pointee-tail-is-generic-errors.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0271]: type mismatch resolving `<T as Pointee>::Metadata == ()`
--> $DIR/pointee-tail-is-generic-errors.rs:13:5
|
LL | is_thin::<T>();
| ^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<T as Pointee>::Metadata`
= help: consider constraining the associated type `<T as Pointee>::Metadata` to `()`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `is_thin`
--> $DIR/pointee-tail-is-generic-errors.rs:20:33
|
LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
| ^^^^^^^^^^^^^ required by this bound in `is_thin`

error[E0271]: type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
--> $DIR/pointee-tail-is-generic-errors.rs:16:5
|
LL | type Opaque = impl std::fmt::Debug + ?Sized;
| ----------------------------- the found opaque type
...
LL | is_thin::<Opaque>();
| ^^^^^^^^^^^^^^^^^ expected `()`, found associated type
|
= note: expected unit type `()`
found associated type `<impl Debug + ?Sized as Pointee>::Metadata`
note: required by a bound in `is_thin`
--> $DIR/pointee-tail-is-generic-errors.rs:20:33
|
LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
| ^^^^^^^^^^^^^ required by this bound in `is_thin`
help: consider constraining the associated type `<impl Debug + ?Sized as Pointee>::Metadata` to `()`
|
LL | type Opaque = impl std::fmt::Debug<Metadata = ()> + ?Sized;
| +++++++++++++++

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0271`.
29 changes: 29 additions & 0 deletions src/test/ui/traits/pointee-tail-is-generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// check-pass
// edition:2018

#![feature(ptr_metadata)]
#![feature(type_alias_impl_trait)]

type Opaque = impl std::future::Future;

fn opaque() -> Opaque {
async {}
}

fn a<T>() {
// type parameter T is known to be sized
is_thin::<T>();
// tail of ADT (which is a type param) is known to be sized
is_thin::<std::cell::Cell<T>>();
// opaque type is known to be sized
is_thin::<Opaque>();
}

fn a2<T: Iterator>() {
// associated type is known to be sized
is_thin::<T::Item>();
}

fn is_thin<T: std::ptr::Pointee<Metadata = ()>>() {}

fn main() {}
2 changes: 1 addition & 1 deletion src/tools/miri