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:
commit
4bb685e471
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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!(),
|
||||
})
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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),
|
||||
}),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -1348,6 +1348,7 @@
|
||||
str_trim,
|
||||
str_trim_end,
|
||||
str_trim_start,
|
||||
strict_provenance,
|
||||
stringify,
|
||||
stringify_macro,
|
||||
struct_field_attributes,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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.
|
||||
|
215
library/alloc/src/boxed/thin.rs
Normal file
215
library/alloc/src/boxed/thin.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
||||
|
26
library/alloc/tests/thin_box.rs
Normal file
26
library/alloc/tests/thin_box.rs
Normal 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>());
|
||||
}
|
@ -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, it’s 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
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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`
|
||||
}
|
||||
```
|
22
src/test/rustdoc/empty-doc-comment.rs
Normal file
22
src/test/rustdoc/empty-doc-comment.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Ensure that empty doc comments don't panic.
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
||||
///
|
||||
///
|
||||
pub struct Foo;
|
||||
|
||||
#[doc = "
|
||||
"]
|
||||
pub mod Mod {
|
||||
//!
|
||||
//!
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
pub mod Another {
|
||||
#![doc = "
|
||||
"]
|
||||
}
|
26
src/test/ui/box/thin_align.rs
Normal file
26
src/test/ui/box/thin_align.rs
Normal 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 {}
|
37
src/test/ui/box/thin_drop.rs
Normal file
37
src/test/ui/box/thin_drop.rs
Normal 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<'_> {}
|
30
src/test/ui/box/thin_new.rs
Normal file
30
src/test/ui/box/thin_new.rs
Normal 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 {}
|
34
src/test/ui/box/thin_zst.rs
Normal file
34
src/test/ui/box/thin_zst.rs
Normal 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 {}
|
@ -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
|
||||
|
19
src/test/ui/feature-gates/feature-gate-strict_provenance.rs
Normal file
19
src/test/ui/feature-gates/feature-gate-strict_provenance.rs
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
7
src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs
Normal file
7
src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs
Normal 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`
|
||||
}
|
19
src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
Normal file
19
src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr
Normal 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
|
||||
|
11
src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
Normal file
11
src/test/ui/lint/lint-strict-provenance-lossy-casts.rs
Normal 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`
|
||||
}
|
23
src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
Normal file
23
src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
Normal 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
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -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`.
|
||||
|
16
src/test/ui/traits/no-fallback-multiple-impls.rs
Normal file
16
src/test/ui/traits/no-fallback-multiple-impls.rs
Normal 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...
|
||||
}
|
9
src/test/ui/traits/no-fallback-multiple-impls.stderr
Normal file
9
src/test/ui/traits/no-fallback-multiple-impls.stderr
Normal 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`.
|
@ -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
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user