Auto merge of #95835 - Dylan-DPC:rollup-l5mf2ad, r=Dylan-DPC

Rollup of 8 pull requests

Successful merges:

 - #90066 (Add new ThinBox type for 1 stack pointer wide heap allocated trait objects)
 - #95374 (assert_uninit_valid: ensure we detect at least arrays of uninhabited types)
 - #95599 (Strict provenance lints)
 - #95751 (Don't report numeric inference ambiguity when we have previous errors)
 - #95764 ([macro_metavar_expr] Add tests to ensure the feature requirement)
 - #95787 (reword panic vs result section to remove recoverable vs unrecoverable framing)
 - #95797 (Remove explicit delimiter token trees from `Delimited`.)
 - #95804 (rustdoc: Fix empty doc comment with backline ICE)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-04-09 04:53:34 +00:00
commit 4bb685e471
40 changed files with 1029 additions and 151 deletions

View File

@ -52,7 +52,10 @@ fn get_horizontal_trim<'a>(lines: &'a [&str], kind: CommentKind) -> Option<Strin
// when we try to compute the "horizontal trim".
let lines = if kind == CommentKind::Block {
// Whatever happens, we skip the first line.
let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 };
let mut i = lines
.get(0)
.map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 })
.unwrap_or(0);
let mut j = lines.len();
while i < j && lines[i].trim().is_empty() {

View File

@ -17,48 +17,24 @@
use rustc_span::symbol::Ident;
use rustc_span::Span;
/// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. The delimiter itself
/// might be `NoDelim`.
/// Contains the sub-token-trees of a "delimited" token tree such as `(a b c)`. The delimiters
/// might be `NoDelim`, but they are not represented explicitly.
#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
struct Delimited {
delim: token::DelimToken,
/// Note: This contains the opening and closing delimiters tokens (e.g. `(` and `)`). Note that
/// these could be `NoDelim`. These token kinds must match `delim`, and the methods below
/// debug_assert this.
all_tts: Vec<TokenTree>,
/// FIXME: #67062 has details about why this is sub-optimal.
tts: Vec<TokenTree>,
}
impl Delimited {
/// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. Panics if
/// the delimiter is `NoDelim`.
fn open_tt(&self) -> &TokenTree {
let tt = self.all_tts.first().unwrap();
debug_assert!(matches!(
tt,
&TokenTree::Token(token::Token { kind: token::OpenDelim(d), .. }) if d == self.delim
));
tt
/// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter.
fn open_tt(&self, span: DelimSpan) -> TokenTree {
TokenTree::token(token::OpenDelim(self.delim), span.open)
}
/// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. Panics if
/// the delimiter is `NoDelim`.
fn close_tt(&self) -> &TokenTree {
let tt = self.all_tts.last().unwrap();
debug_assert!(matches!(
tt,
&TokenTree::Token(token::Token { kind: token::CloseDelim(d), .. }) if d == self.delim
));
tt
}
/// Returns the tts excluding the outer delimiters.
///
/// FIXME: #67062 has details about why this is sub-optimal.
fn inner_tts(&self) -> &[TokenTree] {
// These functions are called for the assertions within them.
let _open_tt = self.open_tt();
let _close_tt = self.close_tt();
&self.all_tts[1..self.all_tts.len() - 1]
/// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter.
fn close_tt(&self, span: DelimSpan) -> TokenTree {
TokenTree::token(token::CloseDelim(self.delim), span.close)
}
}

View File

@ -282,7 +282,7 @@ fn check_binders(
// `MetaVarExpr` can not appear in the LHS of a macro arm
TokenTree::MetaVarExpr(..) => {}
TokenTree::Delimited(_, ref del) => {
for tt in del.inner_tts() {
for tt in &del.tts {
check_binders(sess, node_id, tt, macros, binders, ops, valid);
}
}
@ -345,7 +345,7 @@ fn check_occurrences(
check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name);
}
TokenTree::Delimited(_, ref del) => {
check_nested_occurrences(sess, node_id, del.inner_tts(), macros, binders, ops, valid);
check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid);
}
TokenTree::Sequence(_, ref seq) => {
let ops = ops.push(seq.kleene);
@ -432,20 +432,14 @@ fn check_nested_occurrences(
{
let macro_rules = state == NestedMacroState::MacroRulesNotName;
state = NestedMacroState::Empty;
let rest = check_nested_macro(
sess,
node_id,
macro_rules,
del.inner_tts(),
&nested_macros,
valid,
);
let rest =
check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, valid);
// If we did not check the whole macro definition, then check the rest as if outside
// the macro definition.
check_nested_occurrences(
sess,
node_id,
&del.inner_tts()[rest..],
&del.tts[rest..],
macros,
binders,
ops,

View File

@ -151,9 +151,11 @@ fn inner(
TokenTree::Token(token) => {
locs.push(MatcherLoc::Token { token: token.clone() });
}
TokenTree::Delimited(_, delimited) => {
TokenTree::Delimited(span, delimited) => {
locs.push(MatcherLoc::Delimited);
inner(sess, &delimited.all_tts, locs, next_metavar, seq_depth);
inner(sess, &[delimited.open_tt(*span)], locs, next_metavar, seq_depth);
inner(sess, &delimited.tts, locs, next_metavar, seq_depth);
inner(sess, &[delimited.close_tt(*span)], locs, next_metavar, seq_depth);
}
TokenTree::Sequence(_, seq) => {
// We can't determine `idx_first_after` and construct the final
@ -293,7 +295,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
.map(|tt| match tt {
TokenTree::MetaVarDecl(..) => 1,
TokenTree::Sequence(_, seq) => seq.num_captures,
TokenTree::Delimited(_, delim) => count_metavar_decls(delim.inner_tts()),
TokenTree::Delimited(_, delim) => count_metavar_decls(&delim.tts),
TokenTree::Token(..) => 0,
TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(),
})

View File

@ -263,9 +263,7 @@ fn generic_extension<'cx, 'tt>(
// Ignore the delimiters on the RHS.
let rhs = match &rhses[i] {
mbe::TokenTree::Delimited(_, delimited) => {
delimited.inner_tts().to_vec().clone()
}
mbe::TokenTree::Delimited(_, delimited) => delimited.tts.to_vec(),
_ => cx.span_bug(sp, "malformed macro rhs"),
};
let arm_span = rhses[i].span();
@ -470,17 +468,16 @@ pub fn compile_declarative_macro(
.iter()
.map(|m| {
if let MatchedTokenTree(ref tt) = *m {
let mut tts = vec![];
mbe::quoted::parse(
let tt = mbe::quoted::parse(
tt.clone().into(),
true,
&sess.parse_sess,
def.id,
features,
edition,
&mut tts,
);
let tt = tts.pop().unwrap();
)
.pop()
.unwrap();
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def, &tt);
return tt;
}
@ -495,17 +492,16 @@ pub fn compile_declarative_macro(
.iter()
.map(|m| {
if let MatchedTokenTree(ref tt) = *m {
let mut tts = vec![];
mbe::quoted::parse(
return mbe::quoted::parse(
tt.clone().into(),
false,
&sess.parse_sess,
def.id,
features,
edition,
&mut tts,
);
return tts.pop().unwrap();
)
.pop()
.unwrap();
}
sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
@ -544,7 +540,7 @@ pub fn compile_declarative_macro(
// Ignore the delimiters around the matcher.
match lhs {
mbe::TokenTree::Delimited(_, delimited) => {
mbe::macro_parser::compute_locs(&sess.parse_sess, delimited.inner_tts())
mbe::macro_parser::compute_locs(&sess.parse_sess, &delimited.tts)
}
_ => sess.parse_sess.span_diagnostic.span_bug(def.span, "malformed macro lhs"),
}
@ -576,7 +572,7 @@ fn check_lhs_nt_follows(
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let mbe::TokenTree::Delimited(_, delimited) = lhs {
check_matcher(sess, features, def, delimited.inner_tts())
check_matcher(sess, features, def, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
sess.span_diagnostic.span_err(lhs.span(), msg);
@ -597,7 +593,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
| TokenTree::MetaVarDecl(..)
| TokenTree::MetaVarExpr(..) => (),
TokenTree::Delimited(_, ref del) => {
if !check_lhs_no_empty_seq(sess, del.inner_tts()) {
if !check_lhs_no_empty_seq(sess, &del.tts) {
return false;
}
}
@ -692,9 +688,9 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
| TokenTree::MetaVarExpr(..) => {
first.replace_with(tt.clone());
}
TokenTree::Delimited(_span, ref delimited) => {
build_recur(sets, delimited.inner_tts());
first.replace_with(delimited.open_tt().clone());
TokenTree::Delimited(span, ref delimited) => {
build_recur(sets, &delimited.tts);
first.replace_with(delimited.open_tt(span));
}
TokenTree::Sequence(sp, ref seq_rep) => {
let subfirst = build_recur(sets, &seq_rep.tts);
@ -758,8 +754,8 @@ fn first(&self, tts: &[mbe::TokenTree]) -> TokenSet {
first.add_one(tt.clone());
return first;
}
TokenTree::Delimited(_span, ref delimited) => {
first.add_one(delimited.open_tt().clone());
TokenTree::Delimited(span, ref delimited) => {
first.add_one(delimited.open_tt(span));
return first;
}
TokenTree::Sequence(sp, ref seq_rep) => {
@ -945,9 +941,9 @@ fn check_matcher_core(
suffix_first = build_suffix_first();
}
}
TokenTree::Delimited(_span, ref d) => {
let my_suffix = TokenSet::singleton(d.close_tt().clone());
check_matcher_core(sess, features, def, first_sets, d.inner_tts(), &my_suffix);
TokenTree::Delimited(span, ref d) => {
let my_suffix = TokenSet::singleton(d.close_tt(span));
check_matcher_core(sess, features, def, first_sets, &d.tts, &my_suffix);
// don't track non NT tokens
last.replace_with_irrelevant();

View File

@ -45,8 +45,10 @@ pub(super) fn parse(
node_id: NodeId,
features: &Features,
edition: Edition,
result: &mut Vec<TokenTree>,
) {
) -> Vec<TokenTree> {
// Will contain the final collection of `self::TokenTree`
let mut result = Vec::new();
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
// additional trees if need be.
let mut trees = input.trees();
@ -113,6 +115,7 @@ pub(super) fn parse(
_ => result.push(tree),
}
}
result
}
/// Asks for the `macro_metavar_expr` feature if it is not already declared
@ -205,8 +208,7 @@ fn parse_tree(
// If we didn't find a metavar expression above, then we must have a
// repetition sequence in the macro (e.g. `$(pat)*`). Parse the
// contents of the sequence itself
let mut sequence = vec![];
parse(tts, parsing_patterns, sess, node_id, features, edition, &mut sequence);
let sequence = parse(tts, parsing_patterns, sess, node_id, features, edition);
// Get the Kleene operator and optional separator
let (separator, kleene) =
parse_sep_and_kleene_op(&mut trees, delim_span.entire(), sess);
@ -269,15 +271,13 @@ fn parse_tree(
// `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
// descend into the delimited set and further parse it.
tokenstream::TokenTree::Delimited(span, delim, tts) => {
let mut all_tts = vec![];
// Add the explicit open and close delimiters, which
// `tokenstream::TokenTree::Delimited` lacks.
all_tts.push(TokenTree::token(token::OpenDelim(delim), span.open));
parse(tts, parsing_patterns, sess, node_id, features, edition, &mut all_tts);
all_tts.push(TokenTree::token(token::CloseDelim(delim), span.close));
TokenTree::Delimited(span, Lrc::new(Delimited { delim, all_tts }))
}
tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
span,
Lrc::new(Delimited {
delim,
tts: parse(tts, parsing_patterns, sess, node_id, features, edition),
}),
),
}
}

View File

@ -10,7 +10,7 @@
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_span::hygiene::{LocalExpnId, Transparency};
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::Span;
use smallvec::{smallvec, SmallVec};
use std::mem;
@ -34,14 +34,8 @@ enum Frame {
impl Frame {
/// Construct a new frame around the delimited set of tokens.
fn new(mut tts: Vec<mbe::TokenTree>) -> Frame {
// Need to add empty delimiters.
let open_tt = mbe::TokenTree::token(token::OpenDelim(token::NoDelim), DUMMY_SP);
let close_tt = mbe::TokenTree::token(token::CloseDelim(token::NoDelim), DUMMY_SP);
tts.insert(0, open_tt);
tts.push(close_tt);
let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, all_tts: tts });
fn new(tts: Vec<mbe::TokenTree>) -> Frame {
let forest = Lrc::new(mbe::Delimited { delim: token::NoDelim, tts });
Frame::Delimited { forest, idx: 0, span: DelimSpan::dummy() }
}
}
@ -52,7 +46,7 @@ impl Iterator for Frame {
fn next(&mut self) -> Option<mbe::TokenTree> {
match *self {
Frame::Delimited { ref forest, ref mut idx, .. } => {
let res = forest.inner_tts().get(*idx).cloned();
let res = forest.tts.get(*idx).cloned();
*idx += 1;
res
}
@ -388,7 +382,7 @@ fn lockstep_iter_size(
use mbe::TokenTree;
match *tree {
TokenTree::Delimited(_, ref delimited) => {
delimited.inner_tts().iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
size.with(lockstep_iter_size(tt, interpolations, repeats))
})
}

View File

@ -505,6 +505,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
(active, static_nobundle, "1.16.0", Some(37403), None),
/// Allows attributes on expressions and non-item statements.
(active, stmt_expr_attributes, "1.6.0", Some(15701), None),
/// Allows lints part of the strict provenance effort.
(active, strict_provenance, "1.61.0", Some(95228), None),
/// Allows the use of `#[target_feature]` on safe functions.
(active, target_feature_11, "1.45.0", Some(69098), None),
/// Allows using `#[thread_local]` on `static` items.

View File

@ -2648,6 +2648,96 @@
};
}
declare_lint! {
/// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
/// and a pointer.
///
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(fuzzy_provenance_casts)]
///
/// fn main() {
/// let _dangling = 16_usize as *const u8;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is part of the strict provenance effort, see [issue #95228].
/// Casting an integer to a pointer is considered bad style, as a pointer
/// contains, besides the *address* also a *provenance*, indicating what
/// memory the pointer is allowed to read/write. Casting an integer, which
/// doesn't have provenance, to a pointer requires the compiler to assign
/// (guess) provenance. The compiler assigns "all exposed valid" (see the
/// docs of [`ptr::from_exposed_addr`] for more information about this
/// "exposing"). This penalizes the optimiser and is not well suited for
/// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
/// platforms).
///
/// It is much better to use [`ptr::with_addr`] instead to specify the
/// provenance you want. If using this function is not possible because the
/// code relies on exposed provenance then there is as an escape hatch
/// [`ptr::from_exposed_addr`].
///
/// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
/// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr
/// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr
pub FUZZY_PROVENANCE_CASTS,
Allow,
"a fuzzy integer to pointer cast is used",
@feature_gate = sym::strict_provenance;
}
declare_lint! {
/// The `lossy_provenance_casts` lint detects an `as` cast between a pointer
/// and an integer.
///
/// ### Example
///
/// ```rust
/// #![feature(strict_provenance)]
/// #![warn(lossy_provenance_casts)]
///
/// fn main() {
/// let x: u8 = 37;
/// let _addr: usize = &x as *const u8 as usize;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is part of the strict provenance effort, see [issue #95228].
/// Casting a pointer to an integer is a lossy operation, because beyond
/// just an *address* a pointer may be associated with a particular
/// *provenance*. This information is used by the optimiser and for dynamic
/// analysis/dynamic program verification (e.g. Miri or CHERI platforms).
///
/// Since this cast is lossy, it is considered good style to use the
/// [`ptr::addr`] method instead, which has a similar effect, but doesn't
/// "expose" the pointer provenance. This improves optimisation potential.
/// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information
/// about exposing pointer provenance.
///
/// If your code can't comply with strict provenance and needs to expose
/// the provenance, then there is [`ptr::expose_addr`] as an escape hatch,
/// which preserves the behaviour of `as usize` casts while being explicit
/// about the semantics.
///
/// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
/// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr
/// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr
pub LOSSY_PROVENANCE_CASTS,
Allow,
"a lossy pointer to integer cast is used",
@feature_gate = sym::strict_provenance;
}
declare_lint! {
/// The `const_evaluatable_unchecked` lint detects a generic constant used
/// in a type.
@ -3101,6 +3191,8 @@
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
CENUM_IMPL_DROP_CAST,
FUZZY_PROVENANCE_CASTS,
LOSSY_PROVENANCE_CASTS,
CONST_EVALUATABLE_UNCHECKED,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
MUST_NOT_SUSPEND,

View File

@ -1348,6 +1348,7 @@
str_trim,
str_trim_end,
str_trim_start,
strict_provenance,
stringify,
stringify_macro,
struct_field_attributes,

View File

@ -36,6 +36,7 @@
use rustc_span::{ExpnKind, Span, DUMMY_SP};
use std::fmt;
use std::iter;
use std::ops::ControlFlow;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
@ -2226,9 +2227,10 @@ fn annotate_source_of_ambiguity(
post.dedup();
if self.is_tainted_by_errors()
&& crate_names.len() == 1
&& ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
&& spans.len() == 0
&& (crate_names.len() == 1
&& spans.len() == 0
&& ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
|| predicate.visit_with(&mut HasNumericInferVisitor).is_break())
{
// Avoid complaining about other inference issues for expressions like
// `42 >> 1`, where the types are still `{integer}`, but we want to
@ -2666,3 +2668,17 @@ pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
}
}
}
struct HasNumericInferVisitor;
impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor {
type BreakTy = ();
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
ControlFlow::Break(())
} else {
ControlFlow::CONTINUE
}
}
}

View File

@ -807,11 +807,22 @@ pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
// ptr -> *
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
// ptr-addr-cast
(Ptr(m_expr), Int(t_c)) => {
self.lossy_provenance_ptr2int_lint(fcx, t_c);
self.check_ptr_addr_cast(fcx, m_expr)
}
(FnPtr, Int(_)) => {
// FIXME(#95489): there should eventually be a lint for these casts
Ok(CastKind::FnPtrAddrCast)
}
// addr-ptr-cast
(Int(_), Ptr(mt)) => {
self.fuzzy_provenance_int2ptr_lint(fcx);
self.check_addr_ptr_cast(fcx, mt)
}
// fn-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
// prim -> prim
@ -973,6 +984,74 @@ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
}
}
}
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
fcx.tcx.struct_span_lint_hir(
lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
let mut err = err.build(&format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
));
let msg = "use `.addr()` to obtain the address of a pointer";
if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
let scalar_cast = match t_c {
ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
_ => format!(" as {}", self.cast_ty),
};
err.span_suggestion(
self.span,
msg,
format!("({}).addr(){}", snippet, scalar_cast),
Applicability::MaybeIncorrect
);
} else {
err.help(msg);
}
err.help(
"if you can't comply with strict provenance and need to expose the pointer\
provenance you can use `.expose_addr()` instead"
);
err.emit();
},
);
}
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
fcx.tcx.struct_span_lint_hir(
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
let mut err = err.build(&format!(
"strict provenance disallows casting integer `{}` to pointer `{}`",
self.expr_ty, self.cast_ty
));
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
err.span_suggestion(
self.span,
msg,
format!("(...).with_addr({})", snippet),
Applicability::HasPlaceholders,
);
} else {
err.help(msg);
}
err.help(
"if you can't comply with strict provenance and don't have a pointer with \
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
);
err.emit();
},
);
}
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

View File

@ -163,6 +163,11 @@
#[cfg(not(no_global_oom_handling))]
use crate::vec::Vec;
#[unstable(feature = "thin_box", issue = "92791")]
pub use thin::ThinBox;
mod thin;
/// A pointer type for heap allocation.
///
/// See the [module-level documentation](../../std/boxed/index.html) for more.

View File

@ -0,0 +1,215 @@
// Based on
// https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs
// by matthieu-m
use crate::alloc::{self, Layout, LayoutError};
use core::fmt::{self, Debug, Display, Formatter};
use core::marker::{PhantomData, Unsize};
use core::mem;
use core::ops::{Deref, DerefMut};
use core::ptr::Pointee;
use core::ptr::{self, NonNull};
/// ThinBox.
///
/// A thin pointer for heap allocation, regardless of T.
///
/// # Examples
///
/// ```
/// #![feature(thin_box)]
/// use std::boxed::ThinBox;
///
/// let five = ThinBox::new(5);
/// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
///
/// use std::mem::{size_of, size_of_val};
/// let size_of_ptr = size_of::<*const ()>();
/// assert_eq!(size_of_ptr, size_of_val(&five));
/// assert_eq!(size_of_ptr, size_of_val(&thin_slice));
/// ```
#[unstable(feature = "thin_box", issue = "92791")]
pub struct ThinBox<T: ?Sized> {
ptr: WithHeader<<T as Pointee>::Metadata>,
_marker: PhantomData<T>,
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T> ThinBox<T> {
/// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
/// the stack.
///
/// # Examples
///
/// ```
/// #![feature(thin_box)]
/// use std::boxed::ThinBox;
///
/// let five = ThinBox::new(5);
/// ```
#[cfg(not(no_global_oom_handling))]
pub fn new(value: T) -> Self {
let meta = ptr::metadata(&value);
let ptr = WithHeader::new(meta, value);
ThinBox { ptr, _marker: PhantomData }
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<Dyn: ?Sized> ThinBox<Dyn> {
/// Moves a type to the heap with its `Metadata` stored in the heap allocation instead of on
/// the stack.
///
/// # Examples
///
/// ```
/// #![feature(thin_box)]
/// use std::boxed::ThinBox;
///
/// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
/// ```
#[cfg(not(no_global_oom_handling))]
pub fn new_unsize<T>(value: T) -> Self
where
T: Unsize<Dyn>,
{
let meta = ptr::metadata(&value as &Dyn);
let ptr = WithHeader::new(meta, value);
ThinBox { ptr, _marker: PhantomData }
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized + Debug> Debug for ThinBox<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Debug::fmt(self.deref(), f)
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized + Display> Display for ThinBox<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(self.deref(), f)
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized> Deref for ThinBox<T> {
type Target = T;
fn deref(&self) -> &T {
let value = self.data();
let metadata = self.meta();
let pointer = ptr::from_raw_parts(value as *const (), metadata);
unsafe { &*pointer }
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized> DerefMut for ThinBox<T> {
fn deref_mut(&mut self) -> &mut T {
let value = self.data();
let metadata = self.meta();
let pointer = ptr::from_raw_parts_mut::<T>(value as *mut (), metadata);
unsafe { &mut *pointer }
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized> Drop for ThinBox<T> {
fn drop(&mut self) {
unsafe {
let value = self.deref_mut();
let value = value as *mut T;
self.ptr.drop::<T>(value);
}
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized> ThinBox<T> {
fn meta(&self) -> <T as Pointee>::Metadata {
// Safety:
// - NonNull and valid.
unsafe { *self.ptr.header() }
}
fn data(&self) -> *mut u8 {
self.ptr.value()
}
}
/// A pointer to type-erased data, guaranteed to have a header `H` before the pointed-to location.
struct WithHeader<H>(NonNull<u8>, PhantomData<H>);
impl<H> WithHeader<H> {
#[cfg(not(no_global_oom_handling))]
fn new<T>(header: H, value: T) -> WithHeader<H> {
let value_layout = Layout::new::<T>();
let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
// We pass an empty layout here because we do not know which layout caused the
// arithmetic overflow in `Layout::extend` and `handle_alloc_error` takes `Layout` as
// its argument rather than `Result<Layout, LayoutError>`, also this function has been
// stable since 1.28 ._.
//
// On the other hand, look at this gorgeous turbofish!
alloc::handle_alloc_error(Layout::new::<()>());
};
unsafe {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
// Safety:
// - The size is at least `aligned_header_size`.
let ptr = ptr.add(value_offset) as *mut _;
let ptr = NonNull::new_unchecked(ptr);
let result = WithHeader(ptr, PhantomData);
ptr::write(result.header(), header);
ptr::write(result.value().cast(), value);
result
}
}
// Safety:
// - Assumes that `value` can be dereferenced.
unsafe fn drop<T: ?Sized>(&self, value: *mut T) {
unsafe {
// SAFETY: Layout must have been computable if we're in drop
let (layout, value_offset) =
Self::alloc_layout(Layout::for_value_raw(value)).unwrap_unchecked();
ptr::drop_in_place::<T>(value);
// We only drop the value because the Pointee trait requires that the metadata is copy
// aka trivially droppable
alloc::dealloc(self.0.as_ptr().sub(value_offset), layout);
}
}
fn header(&self) -> *mut H {
// Safety:
// - At least `size_of::<H>()` bytes are allocated ahead of the pointer.
// - We know that H will be aligned because the middle pointer is aligned to the greater
// of the alignment of the header and the data and the header size includes the padding
// needed to align the header. Subtracting the header size from the aligned data pointer
// will always result in an aligned header pointer, it just may not point to the
// beginning of the allocation.
unsafe { self.0.as_ptr().sub(Self::header_size()) as *mut H }
}
fn value(&self) -> *mut u8 {
self.0.as_ptr()
}
const fn header_size() -> usize {
mem::size_of::<H>()
}
fn alloc_layout(value_layout: Layout) -> Result<(Layout, usize), LayoutError> {
Layout::new::<H>().extend(value_layout)
}
}

View File

@ -120,6 +120,7 @@
#![feature(nonnull_slice_from_raw_parts)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(receiver_trait)]
#![feature(set_ptr_value)]
#![feature(slice_group_by)]
@ -152,6 +153,7 @@
#![feature(fundamental)]
#![cfg_attr(not(test), feature(generator_trait))]
#![feature(lang_items)]
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(negative_impls)]
#![feature(never_type)]

View File

@ -39,6 +39,7 @@
#![feature(nonnull_slice_from_raw_parts)]
#![feature(panic_update_hook)]
#![feature(slice_flatten)]
#![feature(thin_box)]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
@ -57,6 +58,7 @@
mod slice;
mod str;
mod string;
mod thin_box;
mod vec;
mod vec_deque;

View File

@ -0,0 +1,26 @@
use alloc::boxed::ThinBox;
use core::mem::size_of;
#[test]
fn want_niche_optimization() {
fn uses_niche<T: ?Sized>() -> bool {
size_of::<*const ()>() == size_of::<Option<ThinBox<T>>>()
}
trait Tr {}
assert!(uses_niche::<dyn Tr>());
assert!(uses_niche::<[i32]>());
assert!(uses_niche::<i32>());
}
#[test]
fn want_thin() {
fn is_thin<T: ?Sized>() -> bool {
size_of::<*const ()>() == size_of::<ThinBox<T>>()
}
trait Tr {}
assert!(is_thin::<dyn Tr>());
assert!(is_thin::<[i32]>());
assert!(is_thin::<i32>());
}

View File

@ -24,20 +24,30 @@ See also the macro [`compile_error!`], for raising errors during compilation.
# When to use `panic!` vs `Result`
The Rust model of error handling groups errors into two major categories:
recoverable and unrecoverable errors. For a recoverable error, such as a file
not found error, its reasonable to report the problem to the user and retry
the operation. Unrecoverable errors are always symptoms of bugs, like trying to
access a location beyond the end of an array.
The Rust language provides two complementary systems for constructing /
representing, reporting, propagating, reacting to, and discarding errors. These
responsibilities are collectively known as "error handling." `panic!` and
`Result` are similar in that they are each the primary interface of their
respective error handling systems; however, the meaning these interfaces attach
to their errors and the responsibilities they fulfill within their respective
error handling systems differ.
The Rust language and standard library provides `Result` and `panic!` as parts
of two complementary systems for representing, reporting, propagating, reacting
to, and discarding errors for in these two categories.
The `panic!` macro is used to construct errors that represent a bug that has
been detected in your program. With `panic!` you provide a message that
describes the bug and the language then constructs an error with that message,
reports it, and propagates it for you.
The `panic!` macro is provided to represent unrecoverable errors, whereas the
`Result` enum is provided to represent recoverable errors. For more detailed
information about error handling check out the [book] or the [`std::result`]
module docs.
`Result` on the other hand is used to wrap other types that represent either
the successful result of some computation, `Ok(T)`, or error types that
represent an anticipated runtime failure mode of that computation, `Err(E)`.
`Result` is used alongside user defined types which represent the various
anticipated runtime failure modes that the associated computation could
encounter. `Result` must be propagated manually, often with the the help of the
`?` operator and `Try` trait, and they must be reported manually, often with
the help of the `Error` trait.
For more detailed information about error handling check out the [book] or the
[`std::result`] module docs.
[ounwrap]: Option::unwrap
[runwrap]: Result::unwrap

View File

@ -516,6 +516,14 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
}
}
#[unstable(feature = "thin_box", issue = "92791")]
impl<T: ?Sized + crate::error::Error> crate::error::Error for crate::boxed::ThinBox<T> {
fn source(&self) -> Option<&(dyn crate::error::Error + 'static)> {
use core::ops::Deref;
self.deref().source()
}
}
#[stable(feature = "error_by_ref", since = "1.51.0")]
impl<'a, T: Error + ?Sized> Error for &'a T {
#[allow(deprecated, deprecated_in_future)]

View File

@ -290,6 +290,7 @@
#![feature(get_mut_unchecked)]
#![feature(map_try_insert)]
#![feature(new_uninit)]
#![feature(thin_box)]
#![feature(toowned_clone_into)]
#![feature(try_reserve_kind)]
#![feature(vec_into_raw_parts)]

View File

@ -0,0 +1,22 @@
# `strict_provenance`
The tracking issue for this feature is: [#95228]
[#95228]: https://github.com/rust-lang/rust/issues/95228
-----
The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints.
These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model.
The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`).
## Example
```rust
#![feature(strict_provenance)]
#![warn(fuzzy_provenance_casts)]
fn main() {
let _dangling = 16_usize as *const u8;
//~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8`
}
```

View File

@ -0,0 +1,22 @@
// Ensure that empty doc comments don't panic.
/*!
*/
///
///
pub struct Foo;
#[doc = "
"]
pub mod Mod {
//!
//!
}
/**
*/
pub mod Another {
#![doc = "
"]
}

View File

@ -0,0 +1,26 @@
#![feature(thin_box)]
// run-pass
use std::boxed::ThinBox;
use std::error::Error;
use std::ops::Deref;
use std::fmt;
fn main() {
let expected = "Foo error!";
let a: ThinBox<dyn Error> = ThinBox::new_unsize(Foo(expected));
let a = a.deref();
let msg = a.to_string();
assert_eq!(expected, msg);
}
#[derive(Debug)]
#[repr(align(1024))]
struct Foo(&'static str);
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for Foo {}

View File

@ -0,0 +1,37 @@
#![feature(thin_box)]
// run-pass
use std::boxed::ThinBox;
use std::error::Error;
use std::ops::Deref;
use std::fmt;
fn main() {
let expected = "Foo error!";
let mut dropped = false;
{
let foo = Foo(expected, &mut dropped);
let a: ThinBox<dyn Error> = ThinBox::new_unsize(foo);
let a = a.deref();
let msg = a.to_string();
assert_eq!(expected, msg);
}
assert!(dropped);
}
#[derive(Debug)]
#[repr(align(1024))]
struct Foo<'a>(&'static str, &'a mut bool);
impl Drop for Foo<'_> {
fn drop(&mut self) {
*self.1 = true;
}
}
impl fmt::Display for Foo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for Foo<'_> {}

View File

@ -0,0 +1,30 @@
#![feature(thin_box)]
// run-pass
use std::boxed::ThinBox;
use std::error::Error;
use std::{fmt, mem};
fn main() {
let thin_error: ThinBox<dyn Error> = ThinBox::new_unsize(Foo);
assert_eq!(mem::size_of::<*const i32>(), mem::size_of_val(&thin_error));
println!("{:?}", thin_error);
let thin = ThinBox::new(42i32);
assert_eq!(mem::size_of::<*const i32>(), mem::size_of_val(&thin));
println!("{:?}", thin);
let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]);
assert_eq!(mem::size_of::<*const i32>(), mem::size_of_val(&thin_slice));
println!("{:?}", thin_slice);
}
#[derive(Debug)]
struct Foo;
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "boooo!")
}
}
impl Error for Foo {}

View File

@ -0,0 +1,34 @@
#![feature(thin_box)]
// run-pass
use std::boxed::ThinBox;
use std::error::Error;
use std::{fmt, mem};
use std::ops::DerefMut;
const EXPECTED: &str = "boooo!";
fn main() {
let thin_error: ThinBox<dyn Error> = ThinBox::new_unsize(Foo);
assert_eq!(mem::size_of::<*const i32>(), mem::size_of_val(&thin_error));
let msg = thin_error.to_string();
assert_eq!(EXPECTED, msg);
let mut thin_concrete_error: ThinBox<Foo> = ThinBox::new(Foo);
assert_eq!(mem::size_of::<*const i32>(), mem::size_of_val(&thin_concrete_error));
let msg = thin_concrete_error.to_string();
assert_eq!(EXPECTED, msg);
let inner = thin_concrete_error.deref_mut();
let msg = inner.to_string();
assert_eq!(EXPECTED, msg);
}
#[derive(Debug)]
struct Foo;
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", EXPECTED)
}
}
impl Error for Foo {}

View File

@ -13,7 +13,7 @@ LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x
BorrowError
BorrowMutError
Box<T>
and 42 others
and 43 others
= note: required for the cast to the object type `dyn std::error::Error`
error[E0277]: the trait bound `(): std::error::Error` is not satisfied
@ -31,7 +31,7 @@ LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
BorrowError
BorrowMutError
Box<T>
and 42 others
and 43 others
= note: required for the cast to the object type `(dyn std::error::Error + 'static)`
error: aborting due to 2 previous errors

View File

@ -0,0 +1,19 @@
// check-pass
#![deny(fuzzy_provenance_casts)]
//~^ WARNING unknown lint: `fuzzy_provenance_casts`
//~| WARNING unknown lint: `fuzzy_provenance_casts`
//~| WARNING unknown lint: `fuzzy_provenance_casts`
#![deny(lossy_provenance_casts)]
//~^ WARNING unknown lint: `lossy_provenance_casts`
//~| WARNING unknown lint: `lossy_provenance_casts`
//~| WARNING unknown lint: `lossy_provenance_casts`
fn main() {
// no warnings emitted since the lints are not activated
let _dangling = 16_usize as *const u8;
let x: u8 = 37;
let _addr: usize = &x as *const u8 as usize;
}

View File

@ -0,0 +1,63 @@
warning: unknown lint: `fuzzy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:3:1
|
LL | #![deny(fuzzy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unknown_lints)]` on by default
= note: the `fuzzy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: unknown lint: `lossy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:7:1
|
LL | #![deny(lossy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `lossy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: unknown lint: `fuzzy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:3:1
|
LL | #![deny(fuzzy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `fuzzy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: unknown lint: `lossy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:7:1
|
LL | #![deny(lossy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `lossy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: unknown lint: `fuzzy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:3:1
|
LL | #![deny(fuzzy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `fuzzy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: unknown lint: `lossy_provenance_casts`
--> $DIR/feature-gate-strict_provenance.rs:7:1
|
LL | #![deny(lossy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `lossy_provenance_casts` lint is unstable
= note: see issue #95228 <https://github.com/rust-lang/rust/issues/95228> for more information
= help: add `#![feature(strict_provenance)]` to the crate attributes to enable
warning: 6 warnings emitted

View File

@ -104,6 +104,32 @@ fn main() {
"attempted to instantiate uninhabited type `Bar`"
);
test_panic_msg(
|| mem::uninitialized::<[Foo; 2]>(),
"attempted to instantiate uninhabited type `[Foo; 2]`"
);
test_panic_msg(
|| mem::zeroed::<[Foo; 2]>(),
"attempted to instantiate uninhabited type `[Foo; 2]`"
);
test_panic_msg(
|| MaybeUninit::<[Foo; 2]>::uninit().assume_init(),
"attempted to instantiate uninhabited type `[Foo; 2]`"
);
test_panic_msg(
|| mem::uninitialized::<[Bar; 2]>(),
"attempted to instantiate uninhabited type `[Bar; 2]`"
);
test_panic_msg(
|| mem::zeroed::<[Bar; 2]>(),
"attempted to instantiate uninhabited type `[Bar; 2]`"
);
test_panic_msg(
|| MaybeUninit::<[Bar; 2]>::uninit().assume_init(),
"attempted to instantiate uninhabited type `[Bar; 2]`"
);
// Types that do not like zero-initialziation
test_panic_msg(
|| mem::uninitialized::<fn()>(),
@ -199,7 +225,9 @@ fn main() {
let _val = mem::zeroed::<OneVariant>();
let _val = mem::zeroed::<Option<&'static i32>>();
let _val = mem::zeroed::<MaybeUninit<NonNull<u32>>>();
let _val = mem::zeroed::<[!; 0]>();
let _val = mem::uninitialized::<MaybeUninit<bool>>();
let _val = mem::uninitialized::<[!; 0]>();
// These are UB because they have not been officially blessed, but we await the resolution
// of <https://github.com/rust-lang/unsafe-code-guidelines/issues/71> before doing

View File

@ -0,0 +1,7 @@
#![feature(strict_provenance)]
#![deny(fuzzy_provenance_casts)]
fn main() {
let dangling = 16_usize as *const u8;
//~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const u8`
}

View File

@ -0,0 +1,19 @@
error: strict provenance disallows casting integer `usize` to pointer `*const u8`
--> $DIR/lint-strict-provenance-fuzzy-casts.rs:5:20
|
LL | let dangling = 16_usize as *const u8;
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9
|
LL | #![deny(fuzzy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^
= help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
|
LL | let dangling = (...).with_addr(16_usize);
| ~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

View File

@ -0,0 +1,11 @@
#![feature(strict_provenance)]
#![deny(lossy_provenance_casts)]
fn main() {
let x: u8 = 37;
let addr: usize = &x as *const u8 as usize;
//~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
let addr_32bit = &x as *const u8 as u32;
//~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
}

View File

@ -0,0 +1,23 @@
error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize`
--> $DIR/lint-strict-provenance-lossy-casts.rs:6:23
|
LL | let addr: usize = &x as *const u8 as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()`
|
note: the lint level is defined here
--> $DIR/lint-strict-provenance-lossy-casts.rs:2:9
|
LL | #![deny(lossy_provenance_casts)]
| ^^^^^^^^^^^^^^^^^^^^^^
= help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
--> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
|
LL | let addr_32bit = &x as *const u8 as u32;
| ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
|
= help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
error: aborting due to 2 previous errors

View File

@ -5,5 +5,40 @@ macro_rules! count {
};
}
macro_rules! dollar_dollar {
() => {
macro_rules! bar {
( $$( $$any:tt )* ) => { $$( $$any )* };
//~^ ERROR meta-variable expressions are unstable
//~| ERROR meta-variable expressions are unstable
//~| ERROR meta-variable expressions are unstable
//~| ERROR meta-variable expressions are unstable
}
};
}
macro_rules! index {
( $( $e:stmt ),* ) => {
$( ${ignore(e)} ${index()} )*
//~^ ERROR meta-variable expressions are unstable
//~| ERROR meta-variable expressions are unstable
};
}
macro_rules! ignore {
( $( $i:stmt ),* ) => {{
0 $( + 1 ${ignore(i)} )*
//~^ ERROR meta-variable expressions are unstable
}};
}
macro_rules! length {
( $( $e:stmt ),* ) => {
$( ${ignore(e)} ${length()} )*
//~^ ERROR meta-variable expressions are unstable
//~| ERROR meta-variable expressions are unstable
};
}
fn main() {
}

View File

@ -7,6 +7,87 @@ LL | ${ count(e) }
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error: aborting due to previous error
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:11:16
|
LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
| ^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:11:20
|
LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
| ^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:11:39
|
LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
| ^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:11:43
|
LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
| ^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:22:13
|
LL | $( ${ignore(e)} ${index()} )*
| ^^^^^^^^^^^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:22:26
|
LL | $( ${ignore(e)} ${index()} )*
| ^^^^^^^^^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:30:19
|
LL | 0 $( + 1 ${ignore(i)} )*
| ^^^^^^^^^^^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:37:13
|
LL | $( ${ignore(e)} ${length()} )*
| ^^^^^^^^^^^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error[E0658]: meta-variable expressions are unstable
--> $DIR/required-feature.rs:37:26
|
LL | $( ${ignore(e)} ${length()} )*
| ^^^^^^^^^^
|
= note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
= help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,16 @@
trait Fallback {
fn foo(&self) {}
}
impl Fallback for i32 {}
impl Fallback for u64 {}
impl Fallback for usize {}
fn main() {
missing();
//~^ ERROR cannot find function `missing` in this scope
0.foo();
// But then we shouldn't report an inference ambiguity here...
}

View File

@ -0,0 +1,9 @@
error[E0425]: cannot find function `missing` in this scope
--> $DIR/no-fallback-multiple-impls.rs:12:5
|
LL | missing();
| ^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.

View File

@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
fn main() {
10.dup::<i32>(); //~ ERROR type annotations needed
10.dup::<i32>();
//~^ ERROR this associated function takes 0 generic arguments but 1
10.blah::<i32, i32>(); //~ ERROR type annotations needed
10.blah::<i32, i32>();
//~^ ERROR this associated function takes 1 generic argument but 2
(Box::new(10) as Box<dyn bar>).dup();
//~^ ERROR E0038

View File

@ -79,35 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
= note: required by cast to type `Box<dyn bar>`
error[E0283]: type annotations needed
--> $DIR/test-2.rs:9:8
|
LL | 10.dup::<i32>();
| ^^^ cannot infer type for type `{integer}`
|
note: multiple `impl`s satisfying `{integer}: bar` found
--> $DIR/test-2.rs:5:1
|
LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
| ^^^^^^^^^^^^^^^^
LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
| ^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
error[E0283]: type annotations needed
--> $DIR/test-2.rs:11:8
|
LL | 10.blah::<i32, i32>();
| ^^^^ cannot infer type for type `{integer}`
|
note: multiple `impl`s satisfying `{integer}: bar` found
--> $DIR/test-2.rs:5:1
|
LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
| ^^^^^^^^^^^^^^^^
LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
| ^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0038, E0107, E0283.
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.