Auto merge of #94935 - matthiaskrgr:rollup-2o2kyz6, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #90621 (Stabilise `aarch64_target_feature`) - #93977 (Type params and assoc types have unit metadata if they are sized) - #94670 (Improve `expect` impl and handle `#[expect(unfulfilled_lint_expectations)]` (RFC 2383)) - #94884 (Fix remaining meta-variable expression TODOs) - #94931 (update miri) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2184c7c568
28 changed files with 397 additions and 117 deletions
|
@ -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.
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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`"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,6 +278,7 @@ symbols! {
|
|||
_task_context,
|
||||
a32,
|
||||
aarch64_target_feature,
|
||||
aarch64_ver_target_feature,
|
||||
abi,
|
||||
abi_amdgpu_kernel,
|
||||
abi_avr_interrupt,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
src/test/ui/traits/pointee-tail-is-generic-errors.rs
Normal file
22
src/test/ui/traits/pointee-tail-is-generic-errors.rs
Normal file
|
@ -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
src/test/ui/traits/pointee-tail-is-generic-errors.stderr
Normal file
40
src/test/ui/traits/pointee-tail-is-generic-errors.stderr
Normal file
|
@ -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
src/test/ui/traits/pointee-tail-is-generic.rs
Normal file
29
src/test/ui/traits/pointee-tail-is-generic.rs
Normal file
|
@ -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() {}
|
|
@ -1 +1 @@
|
|||
Subproject commit a12a48bf723e0e13f043979a7f79861d975e7187
|
||||
Subproject commit 7bc0c986217629e6c831edcb133532023a5aec63
|
Loading…
Add table
Reference in a new issue