Auto merge of #146418 - matthiaskrgr:rollup-za0lrux, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang/rust#145327 (std: make address resolution weirdness local to SGX)
 - rust-lang/rust#145879 (default auto traits: use default supertraits instead of `Self: Trait` bounds on associated items)
 - rust-lang/rust#146123 (Suggest examples of format specifiers in error messages)
 - rust-lang/rust#146311 (Minor symbol comment fixes.)
 - rust-lang/rust#146322 (Make Barrier RefUnwindSafe again)
 - rust-lang/rust#146327 (Add tests for deref on pin)
 - rust-lang/rust#146340 (Strip frontmatter in fewer places)
 - rust-lang/rust#146342 (Improve C-variadic error messages: part 2)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-09-10 21:30:05 +00:00
commit f4665ab836
81 changed files with 1607 additions and 858 deletions

View file

@ -2284,6 +2284,54 @@ pub struct FnSig {
pub span: Span,
}
impl FnSig {
/// Return a span encompassing the header, or where to insert it if empty.
pub fn header_span(&self) -> Span {
match self.header.ext {
Extern::Implicit(span) | Extern::Explicit(_, span) => {
return self.span.with_hi(span.hi());
}
Extern::None => {}
}
match self.header.safety {
Safety::Unsafe(span) | Safety::Safe(span) => return self.span.with_hi(span.hi()),
Safety::Default => {}
};
if let Some(coroutine_kind) = self.header.coroutine_kind {
return self.span.with_hi(coroutine_kind.span().hi());
}
if let Const::Yes(span) = self.header.constness {
return self.span.with_hi(span.hi());
}
self.span.shrink_to_lo()
}
/// The span of the header's safety, or where to insert it if empty.
pub fn safety_span(&self) -> Span {
match self.header.safety {
Safety::Unsafe(span) | Safety::Safe(span) => span,
Safety::Default => {
// Insert after the `coroutine_kind` if available.
if let Some(extern_span) = self.header.ext.span() {
return extern_span.shrink_to_lo();
}
// Insert right at the front of the signature.
self.header_span().shrink_to_hi()
}
}
}
/// The span of the header's extern, or where to insert it if empty.
pub fn extern_span(&self) -> Span {
self.header.ext.span().unwrap_or(self.safety_span().shrink_to_hi())
}
}
/// A constraint on an associated item.
///
/// ### Examples
@ -3526,6 +3574,13 @@ impl Extern {
None => Extern::Implicit(span),
}
}
pub fn span(self) -> Option<Span> {
match self {
Extern::None => None,
Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span),
}
}
}
/// A function header.
@ -3534,12 +3589,12 @@ impl Extern {
/// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
#[derive(Clone, Copy, Encodable, Decodable, Debug, Walkable)]
pub struct FnHeader {
/// Whether this is `unsafe`, or has a default safety.
pub safety: Safety,
/// Whether this is `async`, `gen`, or nothing.
pub coroutine_kind: Option<CoroutineKind>,
/// The `const` keyword, if any
pub constness: Const,
/// Whether this is `async`, `gen`, or nothing.
pub coroutine_kind: Option<CoroutineKind>,
/// Whether this is `unsafe`, or has a default safety.
pub safety: Safety,
/// The `extern` keyword and corresponding ABI string, if any.
pub ext: Extern,
}
@ -3553,38 +3608,6 @@ impl FnHeader {
|| matches!(constness, Const::Yes(_))
|| !matches!(ext, Extern::None)
}
/// Return a span encompassing the header, or none if all options are default.
pub fn span(&self) -> Option<Span> {
fn append(a: &mut Option<Span>, b: Span) {
*a = match a {
None => Some(b),
Some(x) => Some(x.to(b)),
}
}
let mut full_span = None;
match self.safety {
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
Safety::Default => {}
};
if let Some(coroutine_kind) = self.coroutine_kind {
append(&mut full_span, coroutine_kind.span());
}
if let Const::Yes(span) = self.constness {
append(&mut full_span, span);
}
match self.ext {
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
Extern::None => {}
}
full_span
}
}
impl Default for FnHeader {

View file

@ -2101,17 +2101,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
{
return;
}
if self.tcx.features().more_maybe_bounds() {
return;
}
}
RelaxedBoundPolicy::Forbidden(reason) => {
if self.tcx.features().more_maybe_bounds() {
return;
}
match reason {
RelaxedBoundForbiddenReason::TraitObjectTy => {
if self.tcx.features().more_maybe_bounds() {
return;
}
self.dcx().span_err(
span,
"relaxed bounds are not permitted in trait object types",
@ -2119,6 +2116,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return;
}
RelaxedBoundForbiddenReason::SuperTrait => {
if self.tcx.features().more_maybe_bounds() {
return;
}
let mut diag = self.dcx().struct_span_err(
span,
"relaxed bounds are not permitted in supertrait bounds",

View file

@ -57,8 +57,6 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim
.label = {ast_passes_auto_super_lifetime}
.suggestion = remove the super traits or lifetime bounds
ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
.cannot_have = cannot have a body
.invalid = the invalid body
@ -66,6 +64,19 @@ ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
ast_passes_c_variadic_associated_function = associated functions cannot have a C variable argument list
ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"` functions
.label = `extern "{$abi}"` because of this
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
ast_passes_c_variadic_must_be_unsafe =
functions with a C variable argument list must be unsafe
.suggestion = add the `unsafe` keyword to this definition
ast_passes_c_variadic_no_extern = `...` is not supported for non-extern functions
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadic
.const = `const` because of this
.variadic = C-variadic because of this
@ -84,6 +95,10 @@ ast_passes_const_without_body =
ast_passes_constraint_on_negative_bound =
associated type constraints not allowed on negative bounds
ast_passes_coroutine_and_c_variadic = functions cannot be both `{$coroutine_kind}` and C-variadic
.const = `{$coroutine_kind}` because of this
.variadic = C-variadic because of this
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
.label = not supported
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax

View file

@ -492,7 +492,7 @@ impl<'a> AstValidator<'a> {
}
if !spans.is_empty() {
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
let header_span = sig.header_span();
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
let padding = if header_span.is_empty() { "" } else { " " };
@ -685,22 +685,53 @@ impl<'a> AstValidator<'a> {
});
}
if let Some(coroutine_kind) = sig.header.coroutine_kind {
self.dcx().emit_err(errors::CoroutineAndCVariadic {
spans: vec![coroutine_kind.span(), variadic_param.span],
coroutine_kind: coroutine_kind.as_str(),
coroutine_span: coroutine_kind.span(),
variadic_span: variadic_param.span,
});
}
match fn_ctxt {
FnCtxt::Foreign => return,
FnCtxt::Free => match sig.header.ext {
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
| Extern::Explicit(StrLit { symbol_unescaped: sym::C_dash_unwind, .. }, _)
| Extern::Implicit(_)
if matches!(sig.header.safety, Safety::Unsafe(_)) =>
{
return;
Extern::Implicit(_) => {
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
_ => {}
},
FnCtxt::Assoc(_) => {}
};
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
self.dcx().emit_err(errors::CVariadicBadExtern {
span: variadic_param.span,
abi: symbol_unescaped,
extern_span: sig.extern_span(),
});
}
self.dcx().emit_err(errors::BadCVariadic { span: variadic_param.span });
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
span: variadic_param.span,
unsafe_span: sig.safety_span(),
});
}
}
Extern::None => {
let err = errors::CVariadicNoExtern { span: variadic_param.span };
self.dcx().emit_err(err);
}
},
FnCtxt::Assoc(_) => {
// For now, C variable argument lists are unsupported in associated functions.
let err = errors::CVariadicAssociatedFunction { span: variadic_param.span };
self.dcx().emit_err(err);
}
}
}
fn check_item_named(&self, ident: Ident, kind: &str) {

View file

@ -319,12 +319,46 @@ pub(crate) struct ExternItemAscii {
}
#[derive(Diagnostic)]
#[diag(ast_passes_bad_c_variadic)]
pub(crate) struct BadCVariadic {
#[diag(ast_passes_c_variadic_associated_function)]
pub(crate) struct CVariadicAssociatedFunction {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_no_extern)]
#[help]
pub(crate) struct CVariadicNoExtern {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_must_be_unsafe)]
pub(crate) struct CVariadicMustBeUnsafe {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "unsafe ",
style = "verbose"
)]
pub unsafe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_c_variadic_bad_extern)]
#[help]
pub(crate) struct CVariadicBadExtern {
#[primary_span]
pub span: Span,
pub abi: Symbol,
#[label]
pub extern_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_item_underscore)]
pub(crate) struct ItemUnderscore<'a> {
@ -659,6 +693,18 @@ pub(crate) struct ConstAndCVariadic {
pub variadic_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_coroutine_and_c_variadic)]
pub(crate) struct CoroutineAndCVariadic {
#[primary_span]
pub spans: Vec<Span>,
pub coroutine_kind: &'static str,
#[label(ast_passes_const)]
pub coroutine_span: Span,
#[label(ast_passes_variadic)]
pub variadic_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_pattern_in_foreign, code = E0130)]
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)

View file

@ -565,6 +565,7 @@ fn make_format_args(
&used,
&args,
&pieces,
&invalid_refs,
detect_foreign_fmt,
str_style,
fmt_str,
@ -645,6 +646,7 @@ fn report_missing_placeholders(
used: &[bool],
args: &FormatArguments,
pieces: &[parse::Piece<'_>],
invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
detect_foreign_fmt: bool,
str_style: Option<usize>,
fmt_str: &str,
@ -762,6 +764,31 @@ fn report_missing_placeholders(
diag.span_label(fmt_span, "formatting specifier missing");
}
if !found_foreign && invalid_refs.is_empty() {
// Show example if user didn't use any format specifiers
let show_example = used.iter().all(|used| !used);
if !show_example {
if unused.len() > 1 {
diag.note(format!("consider adding {} format specifiers", unused.len()));
}
} else {
let original_fmt_str =
if fmt_str.len() >= 1 { &fmt_str[..fmt_str.len() - 1] } else { "" };
let msg = if unused.len() == 1 {
"a format specifier".to_string()
} else {
format!("{} format specifiers", unused.len())
};
let sugg = format!("\"{}{}\"", original_fmt_str, "{}".repeat(unused.len()));
let msg = format!("format specifiers use curly braces, consider adding {msg}");
diag.span_suggestion_verbose(fmt_span, msg, sugg, Applicability::MaybeIncorrect);
}
}
diag.emit();
}

View file

@ -1,3 +1,5 @@
//! The implementation of built-in macros which relate to the file system.
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::sync::Arc;
@ -11,9 +13,11 @@ use rustc_expand::base::{
};
use rustc_expand::module::DirOwnership;
use rustc_lint_defs::BuiltinLintDiag;
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::lexer::StripTokens;
use rustc_parse::parser::ForceCollect;
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::SourceMap;
use rustc_span::{ByteSymbol, Pos, Span, Symbol};
use smallvec::SmallVec;
@ -23,11 +27,7 @@ use crate::util::{
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
};
// These macros all relate to the file system; they either return
// the column/row/filename of the expression, or they include
// a given file into the current one.
/// line!(): expands to the current line number
/// Expand `line!()` to the current line number.
pub(crate) fn expand_line(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -42,7 +42,7 @@ pub(crate) fn expand_line(
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
}
/* column!(): expands to the current column number */
/// Expand `column!()` to the current column number.
pub(crate) fn expand_column(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -57,9 +57,7 @@ pub(crate) fn expand_column(
ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
}
/// file!(): expands to the current filename */
/// The source_file (`loc.file`) contains a bunch more information we could spit
/// out if we wanted.
/// Expand `file!()` to the current filename.
pub(crate) fn expand_file(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -81,6 +79,7 @@ pub(crate) fn expand_file(
)))
}
/// Expand `stringify!($input)`.
pub(crate) fn expand_stringify(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -91,6 +90,7 @@ pub(crate) fn expand_stringify(
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
}
/// Expand `module_path!()` to (a textual representation of) the current module path.
pub(crate) fn expand_mod(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -104,9 +104,9 @@ pub(crate) fn expand_mod(
ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
}
/// include! : parse the given file as an expr
/// This is generally a bad idea because it's going to behave
/// unhygienically.
/// Expand `include!($input)`.
///
/// This works in item and expression position. Notably, it doesn't work in pattern position.
pub(crate) fn expand_include<'cx>(
cx: &'cx mut ExtCtxt<'_>,
sp: Span,
@ -116,39 +116,48 @@ pub(crate) fn expand_include<'cx>(
let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
return ExpandResult::Retry(());
};
let file = match mac {
Ok(file) => file,
let path = match mac {
Ok(path) => path,
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
// The file will be added to the code map by the parser
let file = match resolve_path(&cx.sess, file.as_str(), sp) {
Ok(f) => f,
let path = match resolve_path(&cx.sess, path.as_str(), sp) {
Ok(path) => path,
Err(err) => {
let guar = err.emit();
return ExpandResult::Ready(DummyResult::any(sp, guar));
}
};
let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
// If in the included file we have e.g., `mod bar;`,
// then the path of `bar.rs` should be relative to the directory of `file`.
// then the path of `bar.rs` should be relative to the directory of `path`.
// See https://github.com/rust-lang/rust/pull/69838/files#r395217057 for a discussion.
// `MacroExpander::fully_expand_fragment` later restores, so "stack discipline" is maintained.
let dir_path = file.parent().unwrap_or(&file).to_owned();
let dir_path = path.parent().unwrap_or(&path).to_owned();
cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
struct ExpandInclude<'a> {
p: Parser<'a>,
psess: &'a ParseSess,
path: PathBuf,
node_id: ast::NodeId,
span: Span,
}
impl<'a> MacResult for ExpandInclude<'a> {
fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
let expr = parse_expr(&mut self.p).ok()?;
if self.p.token != token::Eof {
self.p.psess.buffer_lint(
fn make_expr(self: Box<ExpandInclude<'a>>) -> Option<Box<ast::Expr>> {
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
self.psess,
&self.path,
// Don't strip frontmatter for backward compatibility, `---` may be the start of a
// manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either.
StripTokens::Shebang,
Some(self.span),
));
let expr = parse_expr(&mut p).ok()?;
if p.token != token::Eof {
p.psess.buffer_lint(
INCOMPLETE_INCLUDE,
self.p.token.span,
p.token.span,
self.node_id,
BuiltinLintDiag::IncompleteInclude,
);
@ -156,24 +165,27 @@ pub(crate) fn expand_include<'cx>(
Some(expr)
}
fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
fn make_items(self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
let mut p = unwrap_or_emit_fatal(new_parser_from_file(
self.psess,
&self.path,
StripTokens::ShebangAndFrontmatter,
Some(self.span),
));
let mut ret = SmallVec::new();
loop {
match self.p.parse_item(ForceCollect::No) {
match p.parse_item(ForceCollect::No) {
Err(err) => {
err.emit();
break;
}
Ok(Some(item)) => ret.push(item),
Ok(None) => {
if self.p.token != token::Eof {
self.p
.dcx()
.create_err(errors::ExpectedItem {
span: self.p.token.span,
token: &pprust::token_to_string(&self.p.token),
})
.emit();
if p.token != token::Eof {
p.dcx().emit_err(errors::ExpectedItem {
span: p.token.span,
token: &pprust::token_to_string(&p.token),
});
}
break;
@ -184,10 +196,17 @@ pub(crate) fn expand_include<'cx>(
}
}
ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
ExpandResult::Ready(Box::new(ExpandInclude {
psess: cx.psess(),
path,
node_id: cx.current_expansion.lint_node_id,
span: sp,
}))
}
/// `include_str!`: read the given file, insert it as a literal string expr
/// Expand `include_str!($input)` to the content of the UTF-8-encoded file given by path `$input` as a string literal.
///
/// This works in expression, pattern and statement position.
pub(crate) fn expand_include_str(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -206,6 +225,7 @@ pub(crate) fn expand_include_str(
Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) {
Ok(src) => {
let interned_src = Symbol::intern(src);
// MacEager converts the expr into a pat if need be.
MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
}
Err(utf8err) => {
@ -218,6 +238,9 @@ pub(crate) fn expand_include_str(
})
}
/// Expand `include_bytes!($input)` to the content of the file given by path `$input`.
///
/// This works in expression, pattern and statement position.
pub(crate) fn expand_include_bytes(
cx: &mut ExtCtxt<'_>,
sp: Span,
@ -237,6 +260,7 @@ pub(crate) fn expand_include_bytes(
// Don't care about getting the span for the raw bytes,
// because the console can't really show them anyway.
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(ByteSymbol::intern(&bytes)));
// MacEager converts the expr into a pat if need be.
MacEager::expr(expr)
}
Err(dummy) => dummy,

View file

@ -51,6 +51,7 @@ use rustc_lint::unerased_lint_store;
use rustc_metadata::creader::MetadataLoader;
use rustc_metadata::locator;
use rustc_middle::ty::TyCtxt;
use rustc_parse::lexer::StripTokens;
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_session::config::{
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, Sysroot,
@ -1288,10 +1289,15 @@ fn warn_on_confusing_output_filename_flag(
fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> {
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
Input::Str { name, input } => {
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
Input::File(file) => {
new_parser_from_file(&sess.psess, file, StripTokens::ShebangAndFrontmatter, None)
}
Input::Str { name, input } => new_parser_from_source_str(
&sess.psess,
name.clone(),
input.clone(),
StripTokens::ShebangAndFrontmatter,
),
});
parser.parse_inner_attributes()
}

View file

@ -4,6 +4,7 @@ use std::path::{self, Path, PathBuf};
use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
use rustc_attr_parsing::validate_attr;
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_parse::lexer::StripTokens;
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
use rustc_session::Session;
use rustc_session::parse::ParseSess;
@ -67,8 +68,12 @@ pub(crate) fn parse_external_mod(
}
// Actually parse the external file as a module.
let mut parser =
unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span)));
let mut parser = unwrap_or_emit_fatal(new_parser_from_file(
&sess.psess,
&mp.file_path,
StripTokens::ShebangAndFrontmatter,
Some(span),
));
let (inner_attrs, items, inner_span) =
parser.parse_mod(exp!(Eof)).map_err(|err| ModError::ParserError(err))?;
attrs.extend(inner_attrs);

View file

@ -8,7 +8,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult};
use rustc_parse::lexer::nfc_normalize;
use rustc_parse::lexer::{StripTokens, nfc_normalize};
use rustc_parse::parser::Parser;
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
use rustc_proc_macro::bridge::{
@ -485,8 +485,13 @@ impl server::FreeFunctions for Rustc<'_, '_> {
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> {
let name = FileName::proc_macro_source_code(s);
let mut parser =
unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned()));
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
self.psess(),
name,
s.to_owned(),
StripTokens::Nothing,
));
let first_span = parser.token.span.data();
let minus_present = parser.eat(exp!(Minus));

View file

@ -174,12 +174,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
};
if let Node::TraitItem(item) = node {
let mut bounds = Vec::new();
icx.lowerer().add_default_trait_item_bounds(item, &mut bounds);
predicates.extend(bounds);
}
let generics = tcx.generics_of(def_id);
// Below we'll consider the bounds on the type parameters (including `Self`)

View file

@ -1,12 +1,13 @@
use std::assert_matches::assert_matches;
use std::ops::ControlFlow;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::codes::*;
use rustc_errors::struct_span_code_err;
use rustc_hir as hir;
use rustc_hir::PolyTraitRef;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::{AmbigArg, PolyTraitRef};
use rustc_middle::bug;
use rustc_middle::ty::{
self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@ -230,122 +231,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
/// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
/// or associated items.
///
/// To keep backward compatibility with existing code, `experimental_default_bounds` bounds
/// should be added everywhere, including super bounds. However this causes a huge performance
/// costs. For optimization purposes instead of adding default supertraits, bounds
/// are added to the associated items:
///
/// ```ignore(illustrative)
/// // Default bounds are generated in the following way:
/// trait Trait {
/// fn foo(&self) where Self: Leak {}
/// }
///
/// // instead of this:
/// trait Trait: Leak {
/// fn foo(&self) {}
/// }
/// ```
/// It is not always possible to do this because of backward compatibility:
///
/// ```ignore(illustrative)
/// pub trait Trait<Rhs = Self> {}
/// pub trait Trait1 : Trait {}
/// //~^ ERROR: `Rhs` requires `DefaultAutoTrait`, but `Self` is not `DefaultAutoTrait`
/// ```
///
/// or:
///
/// ```ignore(illustrative)
/// trait Trait {
/// type Type where Self: Sized;
/// }
/// trait Trait2<T> : Trait<Type = T> {}
/// //~^ ERROR: `DefaultAutoTrait` required for `Trait2`, by implicit `Self: DefaultAutoTrait` in `Trait::Type`
/// ```
///
/// Therefore, `experimental_default_bounds` are still being added to supertraits if
/// the `SelfTyParam` or `AssocItemConstraint` were found in a trait header.
fn requires_default_supertraits(
&self,
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
hir_generics: &'tcx hir::Generics<'tcx>,
) -> bool {
struct TraitInfoCollector;
impl<'tcx> hir::intravisit::Visitor<'tcx> for TraitInfoCollector {
type Result = ControlFlow<()>;
fn visit_assoc_item_constraint(
&mut self,
_constraint: &'tcx hir::AssocItemConstraint<'tcx>,
) -> Self::Result {
ControlFlow::Break(())
}
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
if matches!(
&t.kind,
hir::TyKind::Path(hir::QPath::Resolved(
_,
hir::Path { res: hir::def::Res::SelfTyParam { .. }, .. },
))
) {
return ControlFlow::Break(());
}
hir::intravisit::walk_ty(self, t)
}
}
let mut found = false;
for bound in hir_bounds {
found |= hir::intravisit::walk_param_bound(&mut TraitInfoCollector, bound).is_break();
}
found |= hir::intravisit::walk_generics(&mut TraitInfoCollector, hir_generics).is_break();
found
}
/// Implicitly add `Self: DefaultAutoTrait` clauses on trait associated items if
/// they are not added as super trait bounds to the trait itself. See
/// `requires_default_supertraits` for more information.
pub(crate) fn add_default_trait_item_bounds(
&self,
trait_item: &hir::TraitItem<'tcx>,
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
) {
let tcx = self.tcx();
if !tcx.sess.opts.unstable_opts.experimental_default_bounds {
return;
}
let parent = tcx.local_parent(trait_item.hir_id().owner.def_id);
let hir::Node::Item(parent_trait) = tcx.hir_node_by_def_id(parent) else {
unreachable!();
};
let (trait_generics, trait_bounds) = match parent_trait.kind {
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
_ => unreachable!(),
};
if !self.requires_default_supertraits(trait_bounds, trait_generics) {
let self_ty_where_predicates = (parent, trait_item.generics.predicates);
self.add_default_traits(
bounds,
tcx.types.self_param,
&[],
Some(self_ty_where_predicates),
trait_item.span,
);
}
}
/// Lazily sets `experimental_default_bounds` to true on trait super bounds.
/// See `requires_default_supertraits` for more information.
/// Adds `experimental_default_bounds` bounds to the supertrait bounds.
pub(crate) fn add_default_super_traits(
&self,
trait_def_id: LocalDefId,
@ -354,21 +240,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_generics: &'tcx hir::Generics<'tcx>,
span: Span,
) {
if !self.tcx().sess.opts.unstable_opts.experimental_default_bounds {
assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias);
// Supertraits for auto trait are unsound according to the unstable book:
// https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits
if self.tcx().trait_is_auto(trait_def_id.to_def_id()) {
return;
}
assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
if self.requires_default_supertraits(hir_bounds, hir_generics) {
let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
self.add_default_traits(
bounds,
self.tcx().types.self_param,
hir_bounds,
Some(self_ty_where_predicates),
span,
);
}
self.add_default_traits(
bounds,
self.tcx().types.self_param,
hir_bounds,
Some((trait_def_id, hir_generics.predicates)),
span,
);
}
pub(crate) fn add_default_traits(

View file

@ -13,7 +13,8 @@ use rustc_lint::LintStore;
use rustc_middle::ty;
use rustc_middle::ty::CurrentGcx;
use rustc_middle::util::Providers;
use rustc_parse::new_parser_from_simple_source_str;
use rustc_parse::lexer::StripTokens;
use rustc_parse::new_parser_from_source_str;
use rustc_parse::parser::attr::AllowLeadingUnsafe;
use rustc_query_impl::QueryCtxt;
use rustc_query_system::query::print_query_stack;
@ -68,7 +69,8 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
};
}
match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
{
Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) {
Ok(meta_item) if parser.token == token::Eof => {
if meta_item.path.segments.len() != 1 {
@ -166,13 +168,15 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`")
};
let mut parser = match new_parser_from_simple_source_str(&psess, filename, s.to_string()) {
Ok(parser) => parser,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
expected_error();
}
};
let mut parser =
match new_parser_from_source_str(&psess, filename, s.to_string(), StripTokens::Nothing)
{
Ok(parser) => parser,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
expected_error();
}
};
let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) {
Ok(meta_item) if parser.token == token::Eof => meta_item,

View file

@ -28,6 +28,7 @@ use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepsType;
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_middle::util::Providers;
use rustc_parse::lexer::StripTokens;
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_passes::{abi_test, input_stats, layout_test};
use rustc_resolve::{Resolver, ResolverOutputs};
@ -52,10 +53,18 @@ pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
let mut krate = sess
.time("parse_crate", || {
let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
Input::File(file) => new_parser_from_file(&sess.psess, file, None),
Input::Str { input, name } => {
new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
}
Input::File(file) => new_parser_from_file(
&sess.psess,
file,
StripTokens::ShebangAndFrontmatter,
None,
),
Input::Str { input, name } => new_parser_from_source_str(
&sess.psess,
name.clone(),
input.clone(),
StripTokens::ShebangAndFrontmatter,
),
});
parser.parse_crate_mod()
})

View file

@ -47,7 +47,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
.explicit_super_predicates_of(def_id)
.iter_identity_copied()
.filter_map(|(pred, _)| pred.as_trait_clause())
.filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized));
.filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized))
.filter(|pred| !cx.tcx.is_default_trait(pred.def_id()));
if direct_super_traits_iter.count() > 1 {
cx.emit_span_lint(
MULTIPLE_SUPERTRAIT_UPCASTABLE,

View file

@ -45,7 +45,7 @@ pub(crate) struct UnmatchedDelim {
}
/// Which tokens should be stripped before lexing the tokens.
pub(crate) enum StripTokens {
pub enum StripTokens {
/// Strip both shebang and frontmatter.
ShebangAndFrontmatter,
/// Strip the shebang but not frontmatter.

View file

@ -54,29 +54,18 @@ pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
}
}
/// Creates a new parser from a source string. On failure, the errors must be consumed via
/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are
/// dropped.
/// Creates a new parser from a source string.
///
/// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`,
/// etc., otherwise a panic will occur when they are dropped.
pub fn new_parser_from_source_str(
psess: &ParseSess,
name: FileName,
source: String,
strip_tokens: StripTokens,
) -> Result<Parser<'_>, Vec<Diag<'_>>> {
let source_file = psess.source_map().new_source_file(name, source);
new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter)
}
/// Creates a new parser from a simple (no shebang, no frontmatter) source string.
///
/// On failure, the errors must be consumed via `unwrap_or_emit_fatal`, `emit`, `cancel`,
/// etc., otherwise a panic will occur when they are dropped.
pub fn new_parser_from_simple_source_str(
psess: &ParseSess,
name: FileName,
source: String,
) -> Result<Parser<'_>, Vec<Diag<'_>>> {
let source_file = psess.source_map().new_source_file(name, source);
new_parser_from_source_file(psess, source_file, StripTokens::Nothing)
new_parser_from_source_file(psess, source_file, strip_tokens)
}
/// Creates a new parser from a filename. On failure, the errors must be consumed via
@ -87,6 +76,7 @@ pub fn new_parser_from_simple_source_str(
pub fn new_parser_from_file<'a>(
psess: &'a ParseSess,
path: &Path,
strip_tokens: StripTokens,
sp: Option<Span>,
) -> Result<Parser<'a>, Vec<Diag<'a>>> {
let sm = psess.source_map();
@ -110,7 +100,7 @@ pub fn new_parser_from_file<'a>(
}
err.emit();
});
new_parser_from_source_file(psess, source_file, StripTokens::ShebangAndFrontmatter)
new_parser_from_source_file(psess, source_file, strip_tokens)
}
pub fn utf8_error<E: EmissionGuarantee>(
@ -172,6 +162,9 @@ fn new_parser_from_source_file(
Ok(parser)
}
/// Given a source string, produces a sequence of token trees.
///
/// NOTE: This only strips shebangs, not frontmatter!
pub fn source_str_to_stream(
psess: &ParseSess,
name: FileName,
@ -179,13 +172,16 @@ pub fn source_str_to_stream(
override_span: Option<Span>,
) -> Result<TokenStream, Vec<Diag<'_>>> {
let source_file = psess.source_map().new_source_file(name, source);
// used mainly for `proc_macro` and the likes, not for our parsing purposes, so don't parse
// frontmatters as frontmatters, but for compatibility reason still strip the shebang
// FIXME(frontmatter): Consider stripping frontmatter in a future edition. We can't strip them
// in the current edition since that would be breaking.
// See also <https://github.com/rust-lang/rust/issues/145520>.
// Alternatively, stop stripping shebangs here, too, if T-lang and crater approve.
source_file_to_stream(psess, source_file, override_span, StripTokens::Shebang)
}
/// Given a source file, produces a sequence of token trees. Returns any buffered errors from
/// parsing the token stream.
/// Given a source file, produces a sequence of token trees.
///
/// Returns any buffered errors from parsing the token stream.
fn source_file_to_stream<'psess>(
psess: &'psess ParseSess,
source_file: Arc<SourceFile>,

View file

@ -22,6 +22,7 @@ use rustc_span::{
};
use termcolor::WriteColor;
use crate::lexer::StripTokens;
use crate::parser::{ForceCollect, Parser};
use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
@ -35,6 +36,7 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> {
psess,
PathBuf::from("bogofile").into(),
source_str,
StripTokens::Nothing,
))
}
@ -2240,7 +2242,7 @@ fn parse_item_from_source_str(
source: String,
psess: &ParseSess,
) -> PResult<'_, Option<Box<ast::Item>>> {
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source))
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing))
.parse_item(ForceCollect::No)
}
@ -2520,7 +2522,8 @@ fn ttdelim_span() {
source: String,
psess: &ParseSess,
) -> PResult<'_, Box<ast::Expr>> {
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr()
unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source, StripTokens::Nothing))
.parse_expr()
}
create_default_session_globals_then(|| {

View file

@ -21,18 +21,17 @@ mod tests;
// The proc macro code for this is in `compiler/rustc_macros/src/symbols.rs`.
symbols! {
// This list includes things that are definitely keywords (e.g. `if`),
// a few things that are definitely not keywords (e.g. the empty symbol,
// `{{root}}`) and things where there is disagreement between people and/or
// documents (such as the Rust Reference) about whether it is a keyword
// (e.g. `_`).
// This list includes things that are definitely keywords (e.g. `if`), a
// few things that are definitely not keywords (e.g. `{{root}}`) and things
// where there is disagreement between people and/or documents (such as the
// Rust Reference) about whether it is a keyword (e.g. `_`).
//
// If you modify this list, adjust any relevant `Symbol::{is,can_be}_*`
// predicates and `used_keywords`. Also consider adding new keywords to the
// `ui/parser/raw/raw-idents.rs` test.
Keywords {
// Special reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
// Special reserved identifiers used internally for unnamed method
// parameters, crate root module, etc.
// Matching predicates: `is_special`/`is_reserved`
//
// tidy-alphabetical-start

View file

@ -95,6 +95,9 @@ impl Error {
pub(crate) const ZERO_TIMEOUT: Self =
const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
pub(crate) const NO_ADDRESSES: Self =
const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
}
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -34,7 +34,6 @@ pub use self::tcp::IntoIncoming;
pub use self::tcp::{Incoming, TcpListener, TcpStream};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::udp::UdpSocket;
use crate::io::{self, ErrorKind};
mod ip_addr;
mod socket_addr;
@ -67,23 +66,3 @@ pub enum Shutdown {
#[stable(feature = "rust1", since = "1.0.0")]
Both,
}
fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
where
F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>,
{
let addrs = match addr.to_socket_addrs() {
Ok(addrs) => addrs,
Err(e) => return f(Err(e)),
};
let mut last_err = None;
for addr in addrs {
match f(Ok(&addr)) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
io::const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
}))
}

View file

@ -167,7 +167,7 @@ impl TcpStream {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream)
net_imp::TcpStream::connect(addr).map(TcpStream)
}
/// Opens a TCP connection to a remote host with a timeout.
@ -782,7 +782,7 @@ impl TcpListener {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener)
net_imp::TcpListener::bind(addr).map(TcpListener)
}
/// Returns the local socket address of this listener.

View file

@ -1,5 +1,5 @@
use crate::io::prelude::*;
use crate::io::{BorrowedBuf, IoSlice, IoSliceMut};
use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut};
use crate::mem::MaybeUninit;
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;

View file

@ -120,7 +120,7 @@ impl UdpSocket {
/// [`Ipv4Addr::UNSPECIFIED`] or [`Ipv6Addr::UNSPECIFIED`].
#[stable(feature = "rust1", since = "1.0.0")]
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
net_imp::UdpSocket::bind(addr).map(UdpSocket)
}
/// Receives a single datagram message on the socket. On success, returns the number
@ -677,7 +677,7 @@ impl UdpSocket {
/// on the platform.
#[stable(feature = "net2_mutators", since = "1.9.0")]
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
super::each_addr(addr, |addr| self.0.connect(addr))
self.0.connect(addr)
}
/// Sends data on the socket to the remote address to which it is connected.

View file

@ -1,3 +1,4 @@
use crate::io::ErrorKind;
use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;

View file

@ -1,4 +1,5 @@
use crate::fmt;
use crate::panic::RefUnwindSafe;
use crate::sync::nonpoison::{Condvar, Mutex};
/// A barrier enables multiple threads to synchronize the beginning
@ -31,6 +32,9 @@ pub struct Barrier {
num_threads: usize,
}
#[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")]
impl RefUnwindSafe for Barrier {}
// The inner state of a double barrier
struct BarrierState {
count: usize,

View file

@ -0,0 +1,57 @@
cfg_select! {
any(
all(target_family = "unix", not(target_os = "l4re")),
target_os = "windows",
target_os = "hermit",
all(target_os = "wasi", target_env = "p2"),
target_os = "solid_asp3",
) => {
mod socket;
pub use socket::*;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::*;
}
all(target_os = "wasi", target_env = "p1") => {
mod wasip1;
pub use wasip1::*;
}
target_os = "xous" => {
mod xous;
pub use xous::*;
}
target_os = "uefi" => {
mod uefi;
pub use uefi::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
}
}
#[cfg_attr(
// Make sure that this is used on some platforms at least.
not(any(target_os = "linux", target_os = "windows")),
allow(dead_code)
)]
fn each_addr<A: crate::net::ToSocketAddrs, F, T>(addr: A, mut f: F) -> crate::io::Result<T>
where
F: FnMut(&crate::net::SocketAddr) -> crate::io::Result<T>,
{
use crate::io::Error;
let mut last_err = None;
for addr in addr.to_socket_addrs()? {
match f(&addr) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}
}
match last_err {
Some(err) => Err(err),
None => Err(Error::NO_ADDRESSES),
}
}

View file

@ -1,3 +1,5 @@
use crate::error;
use crate::fmt::{self, Write};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
use crate::sync::Arc;
@ -5,7 +7,6 @@ use crate::sys::abi::usercalls;
use crate::sys::fd::FileDesc;
use crate::sys::{AsInner, FromInner, IntoInner, TryIntoInner, sgx_ineffective, unsupported};
use crate::time::Duration;
use crate::{error, fmt};
const DEFAULT_FAKE_TTL: u32 = 64;
@ -63,18 +64,52 @@ impl fmt::Debug for TcpStream {
}
}
fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result<String> {
match result {
Ok(saddr) => Ok(saddr.to_string()),
// need to downcast twice because io::Error::into_inner doesn't return the original
// value if the conversion fails
Err(e) => {
if e.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()).is_some() {
Ok(e.into_inner().unwrap().downcast::<NonIpSockAddr>().unwrap().host)
} else {
Err(e)
/// Converts each address in `addr` into a hostname.
///
/// SGX doesn't support DNS resolution but rather accepts hostnames in
/// the same place as socket addresses. So, to make e.g.
/// ```rust
/// TcpStream::connect("example.com:80")`
/// ```
/// work, the DNS lookup returns a special error (`NonIpSockAddr`) instead,
/// which contains the hostname being looked up. When `.to_socket_addrs()`
/// fails, we inspect the error and try recover the hostname from it. If that
/// succeeds, we thus continue with the hostname.
///
/// This is a terrible hack and leads to buggy code. For instance, when users
/// use the result of `.to_socket_addrs()` in their own `ToSocketAddrs`
/// implementation to select from a list of possible URLs, the only URL used
/// will be that of the last item tried.
// FIXME: This is a terrible, terrible hack. Fixing this requires Fortanix to
// add a method for resolving addresses.
fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
where
F: FnMut(&str) -> io::Result<T>,
{
match addr.to_socket_addrs() {
Ok(addrs) => {
let mut last_err = None;
let mut encoded = String::new();
for addr in addrs {
// Format the IP address as a string, reusing the buffer.
encoded.clear();
write!(encoded, "{}", &addr).unwrap();
match f(&encoded) {
Ok(val) => return Ok(val),
Err(err) => last_err = Some(err),
}
}
match last_err {
Some(err) => Err(err),
None => Err(io::Error::NO_ADDRESSES),
}
}
Err(err) => match err.get_ref().and_then(|e| e.downcast_ref::<NonIpSockAddr>()) {
Some(NonIpSockAddr { host }) => f(host),
None => Err(err),
},
}
}
@ -86,17 +121,18 @@ fn addr_to_sockaddr(addr: Option<&str>) -> io::Result<SocketAddr> {
}
impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let addr = io_err_to_addr(addr)?;
let (fd, local_addr, peer_addr) = usercalls::connect_stream(&addr)?;
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
each_addr(addr, |addr| {
let (fd, local_addr, peer_addr) = usercalls::connect_stream(addr)?;
Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) })
})
}
pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
if dur == Duration::default() {
return Err(io::Error::ZERO_TIMEOUT);
}
Self::connect(Ok(addr)) // FIXME: ignoring timeout
Self::connect(addr) // FIXME: ignoring timeout
}
pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
@ -247,10 +283,11 @@ impl fmt::Debug for TcpListener {
}
impl TcpListener {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let addr = io_err_to_addr(addr)?;
let (fd, local_addr) = usercalls::bind_stream(&addr)?;
Ok(TcpListener { inner: Socket::new(fd, local_addr) })
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
each_addr(addr, |addr| {
let (fd, local_addr) = usercalls::bind_stream(addr)?;
Ok(TcpListener { inner: Socket::new(fd, local_addr) })
})
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
@ -316,7 +353,7 @@ impl FromInner<Socket> for TcpListener {
pub struct UdpSocket(!);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
unsupported()
}
@ -436,7 +473,7 @@ impl UdpSocket {
self.0
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
self.0
}
}

View file

@ -3,8 +3,11 @@ mod tests;
use crate::ffi::{c_int, c_void};
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::net::{
Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
};
use crate::sys::common::small_c_string::run_with_cstr;
use crate::sys::net::connection::each_addr;
use crate::sys_common::{AsInner, FromInner};
use crate::time::Duration;
use crate::{cmp, fmt, mem, ptr};
@ -342,14 +345,15 @@ pub struct TcpStream {
}
impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let addr = addr?;
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
init();
return each_addr(addr, inner);
let sock = Socket::new(addr, c::SOCK_STREAM)?;
sock.connect(addr)?;
Ok(TcpStream { inner: sock })
fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
let sock = Socket::new(addr, c::SOCK_STREAM)?;
sock.connect(addr)?;
Ok(TcpStream { inner: sock })
}
}
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
@ -512,48 +516,45 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let addr = addr?;
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
init();
return each_addr(addr, inner);
let sock = Socket::new(addr, c::SOCK_STREAM)?;
fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
let sock = Socket::new(addr, c::SOCK_STREAM)?;
// On platforms with Berkeley-derived sockets, this allows to quickly
// rebind a socket, without needing to wait for the OS to clean up the
// previous one.
//
// On Windows, this allows rebinding sockets which are actively in use,
// which allows “socket hijacking”, so we explicitly don't set it here.
// https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
#[cfg(not(windows))]
setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
// On platforms with Berkeley-derived sockets, this allows to quickly
// rebind a socket, without needing to wait for the OS to clean up the
// previous one.
//
// On Windows, this allows rebinding sockets which are actively in use,
// which allows “socket hijacking”, so we explicitly don't set it here.
// https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
#[cfg(not(windows))]
setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR, 1 as c_int)?;
// Bind our new socket
let (addr, len) = socket_addr_to_c(addr);
cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
// Bind our new socket
let (addr, len) = socket_addr_to_c(addr);
cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
cfg_select! {
target_os = "horizon" => {
let backlog = if cfg!(target_os = "horizon") {
// The 3DS doesn't support a big connection backlog. Sometimes
// it allows up to about 37, but other times it doesn't even
// accept 32. There may be a global limitation causing this.
let backlog = 20;
}
target_os = "haiku" => {
20
} else if cfg!(target_os = "haiku") {
// Haiku does not support a queue length > 32
// https://github.com/haiku/haiku/blob/979a0bc487864675517fb2fab28f87dc8bf43041/headers/posix/sys/socket.h#L81
let backlog = 32;
}
_ => {
32
} else {
// The default for all other platforms
let backlog = 128;
}
}
128
};
// Start listening
cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
Ok(TcpListener { inner: sock })
// Start listening
cvt(unsafe { c::listen(sock.as_raw(), backlog) })?;
Ok(TcpListener { inner: sock })
}
}
#[inline]
@ -639,15 +640,16 @@ pub struct UdpSocket {
}
impl UdpSocket {
pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
let addr = addr?;
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
init();
return each_addr(addr, inner);
let sock = Socket::new(addr, c::SOCK_DGRAM)?;
let (addr, len) = socket_addr_to_c(addr);
cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
Ok(UdpSocket { inner: sock })
fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> {
let sock = Socket::new(addr, c::SOCK_DGRAM)?;
let (addr, len) = socket_addr_to_c(addr);
cvt(unsafe { c::bind(sock.as_raw(), addr.as_ptr(), len as _) })?;
Ok(UdpSocket { inner: sock })
}
}
#[inline]
@ -822,9 +824,13 @@ impl UdpSocket {
Ok(ret as usize)
}
pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
let (addr, len) = socket_addr_to_c(addr?);
cvt_r(|| unsafe { c::connect(self.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
return each_addr(addr, |addr| inner(self, addr));
fn inner(this: &UdpSocket, addr: &SocketAddr) -> io::Result<()> {
let (addr, len) = socket_addr_to_c(addr);
cvt_r(|| unsafe { c::connect(this.inner.as_raw(), addr.as_ptr(), len) }).map(drop)
}
}
}

View file

@ -1,6 +1,7 @@
use super::each_addr;
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
use crate::sync::{Arc, Mutex};
use crate::sys::unsupported;
use crate::time::Duration;
@ -15,13 +16,17 @@ pub struct TcpStream {
}
impl TcpStream {
pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
let inner = tcp::Tcp::connect(addr?, None)?;
Ok(Self {
inner,
read_timeout: Arc::new(Mutex::new(None)),
write_timeout: Arc::new(Mutex::new(None)),
})
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
return each_addr(addr, inner);
fn inner(addr: &SocketAddr) -> io::Result<TcpStream> {
let inner = tcp::Tcp::connect(addr, None)?;
Ok(TcpStream {
inner,
read_timeout: Arc::new(Mutex::new(None)),
write_timeout: Arc::new(Mutex::new(None)),
})
}
}
pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
@ -145,7 +150,7 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
unsupported()
}
@ -195,7 +200,7 @@ impl fmt::Debug for TcpListener {
pub struct UdpSocket(!);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
unsupported()
}
@ -315,7 +320,7 @@ impl UdpSocket {
self.0
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
self.0
}
}

View file

@ -1,13 +1,13 @@
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
use crate::sys::unsupported;
use crate::time::Duration;
pub struct TcpStream(!);
impl TcpStream {
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> {
unsupported()
}
@ -121,7 +121,7 @@ impl fmt::Debug for TcpStream {
pub struct TcpListener(!);
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
unsupported()
}
@ -171,7 +171,7 @@ impl fmt::Debug for TcpListener {
pub struct UdpSocket(!);
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
unsupported()
}
@ -291,7 +291,7 @@ impl UdpSocket {
self.0
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
self.0
}
}

View file

@ -2,7 +2,7 @@
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, ToSocketAddrs};
use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys::fd::WasiFd;
use crate::sys::{err2io, unsupported};
@ -60,7 +60,7 @@ impl FromRawFd for Socket {
}
impl TcpStream {
pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
pub fn connect<A: ToSocketAddrs>(_: A) -> io::Result<TcpStream> {
unsupported()
}
@ -212,7 +212,7 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<TcpListener> {
unsupported()
}
@ -316,7 +316,7 @@ pub struct UdpSocket {
}
impl UdpSocket {
pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
pub fn bind<A: ToSocketAddrs>(_: A) -> io::Result<UdpSocket> {
unsupported()
}
@ -436,7 +436,7 @@ impl UdpSocket {
unsupported()
}
pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
pub fn connect<A: ToSocketAddrs>(&self, _: A) -> io::Result<()> {
unsupported()
}

View file

@ -2,9 +2,10 @@ use core::convert::TryInto;
use core::sync::atomic::{Atomic, AtomicBool, AtomicU16, AtomicUsize, Ordering};
use super::*;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::os::xous::services;
use crate::sync::Arc;
use crate::sys::net::connection::each_addr;
use crate::{fmt, io};
macro_rules! unimpl {
@ -25,16 +26,19 @@ pub struct TcpListener {
}
impl TcpListener {
pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
let mut addr = *socketaddr?;
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
return each_addr(addr, inner);
let fd = TcpListener::bind_inner(&mut addr)?;
return Ok(TcpListener {
fd: Arc::new(AtomicU16::new(fd)),
local: addr,
handle_count: Arc::new(AtomicUsize::new(1)),
nonblocking: Arc::new(AtomicBool::new(false)),
});
fn inner(addr: &SocketAddr) -> io::Result<TcpListener> {
let mut addr = *addr;
let fd = TcpListener::bind_inner(&mut addr)?;
Ok(TcpListener {
fd: Arc::new(AtomicU16::new(fd)),
local: addr,
handle_count: Arc::new(AtomicUsize::new(1)),
nonblocking: Arc::new(AtomicBool::new(false)),
})
}
}
/// This returns the raw fd of a Listener, so that it can also be used by the

View file

@ -3,9 +3,12 @@ use core::sync::atomic::{Atomic, AtomicBool, AtomicU32, AtomicUsize, Ordering};
use super::*;
use crate::fmt;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6};
use crate::net::{
IpAddr, Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs,
};
use crate::os::xous::services;
use crate::sync::Arc;
use crate::sys::net::connection::each_addr;
use crate::time::Duration;
macro_rules! unimpl {
@ -79,8 +82,8 @@ impl TcpStream {
}
}
pub fn connect(socketaddr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
Self::connect_timeout(socketaddr?, Duration::ZERO)
pub fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
each_addr(addr, |addr| Self::connect_timeout(addr, Duration::ZERO))
}
pub fn connect_timeout(addr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {

View file

@ -3,9 +3,10 @@ use core::sync::atomic::{Atomic, AtomicUsize, Ordering};
use super::*;
use crate::cell::Cell;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
use crate::os::xous::services;
use crate::sync::Arc;
use crate::sys::net::connection::each_addr;
use crate::time::Duration;
use crate::{fmt, io};
@ -32,40 +33,45 @@ pub struct UdpSocket {
}
impl UdpSocket {
pub fn bind(socketaddr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
let addr = socketaddr?;
// Construct the request
let mut connect_request = ConnectRequest { raw: [0u8; 4096] };
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
return each_addr(addr, inner);
// Serialize the StdUdpBind structure. This is done "manually" because we don't want to
// make an auto-serdes (like bincode or rkyv) crate a dependency of Xous.
let port_bytes = addr.port().to_le_bytes();
connect_request.raw[0] = port_bytes[0];
connect_request.raw[1] = port_bytes[1];
match addr.ip() {
IpAddr::V4(addr) => {
connect_request.raw[2] = 4;
for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
*dest = src;
fn inner(addr: &SocketAddr) -> io::Result<UdpSocket> {
// Construct the request
let mut connect_request = ConnectRequest { raw: [0u8; 4096] };
// Serialize the StdUdpBind structure. This is done "manually" because we don't want to
// make an auto-serdes (like bincode or rkyv) crate a dependency of Xous.
let port_bytes = addr.port().to_le_bytes();
connect_request.raw[0] = port_bytes[0];
connect_request.raw[1] = port_bytes[1];
match addr.ip() {
IpAddr::V4(addr) => {
connect_request.raw[2] = 4;
for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
*dest = src;
}
}
IpAddr::V6(addr) => {
connect_request.raw[2] = 6;
for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
*dest = src;
}
}
}
IpAddr::V6(addr) => {
connect_request.raw[2] = 6;
for (dest, src) in connect_request.raw[3..].iter_mut().zip(addr.octets()) {
*dest = src;
}
}
}
let response = crate::os::xous::ffi::lend_mut(
services::net_server(),
services::NetLendMut::StdUdpBind.into(),
&mut connect_request.raw,
0,
4096,
);
let response = crate::os::xous::ffi::lend_mut(
services::net_server(),
services::NetLendMut::StdUdpBind.into(),
&mut connect_request.raw,
0,
4096,
);
let Ok((_, valid)) = response else {
return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response"));
};
if let Ok((_, valid)) = response {
// The first four bytes should be zero upon success, and will be nonzero
// for an error.
let response = connect_request.raw;
@ -87,8 +93,9 @@ impl UdpSocket {
));
}
}
let fd = response[1] as u16;
return Ok(UdpSocket {
Ok(UdpSocket {
fd,
local: *addr,
remote: Cell::new(None),
@ -96,9 +103,8 @@ impl UdpSocket {
write_timeout: Cell::new(0),
handle_count: Arc::new(AtomicUsize::new(1)),
nonblocking: Cell::new(false),
});
})
}
Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response"))
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
@ -198,10 +204,11 @@ impl UdpSocket {
self.peek_from(buf).map(|(len, _addr)| len)
}
pub fn connect(&self, maybe_addr: io::Result<&SocketAddr>) -> io::Result<()> {
let addr = maybe_addr?;
self.remote.set(Some(*addr));
Ok(())
pub fn connect<A: ToSocketAddrs>(&self, addr: A) -> io::Result<()> {
each_addr(addr, |addr| {
self.remote.set(Some(*addr));
Ok(())
})
}
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {

View file

@ -1,46 +1,4 @@
cfg_select! {
any(
all(target_family = "unix", not(target_os = "l4re")),
target_os = "windows",
target_os = "hermit",
all(target_os = "wasi", target_env = "p2"),
target_os = "solid_asp3",
) => {
mod connection {
mod socket;
pub use socket::*;
}
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod connection {
mod sgx;
pub use sgx::*;
}
}
all(target_os = "wasi", target_env = "p1") => {
mod connection {
mod wasip1;
pub use wasip1::*;
}
}
target_os = "xous" => {
mod connection {
mod xous;
pub use xous::*;
}
}
target_os = "uefi" => {
mod connection {
mod uefi;
pub use uefi::*;
}
}
_ => {
mod connection {
mod unsupported;
pub use unsupported::*;
}
}
}
/// This module contains the implementations of `TcpStream`, `TcpListener` and
/// `UdpSocket` as well as related functionality like DNS resolving.
mod connection;
pub use connection::*;

View file

@ -1,3 +1,4 @@
use std::panic::RefUnwindSafe;
use std::sync::mpsc::{TryRecvError, channel};
use std::sync::{Arc, Barrier};
use std::thread;
@ -33,3 +34,11 @@ fn test_barrier() {
}
assert!(leader_found);
}
/// Asserts that `Barrier` is ref unwind safe.
///
/// See <https://github.com/rust-lang/rust/issues/146087>.
const _: () = {
const fn check_ref_unwind_safe<T: RefUnwindSafe>() {}
check_ref_unwind_safe::<Barrier>();
};

View file

@ -3,6 +3,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast_pretty::pprust::PrintState;
use rustc_ast_pretty::pprust::state::State as Printer;
use rustc_middle::ty::TyCtxt;
use rustc_parse::lexer::StripTokens;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::{FileName, Span};
@ -64,14 +65,18 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String
// Create a Parser.
let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec());
let file_name = FileName::macro_expansion_source_code(&snippet);
let mut parser =
match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) {
Ok(parser) => parser,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
return None;
}
};
let mut parser = match rustc_parse::new_parser_from_source_str(
&psess,
file_name,
snippet.clone(),
StripTokens::Nothing,
) {
Ok(parser) => parser,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
return None;
}
};
// Reparse a single token tree.
if parser.token == token::Eof {

View file

@ -10,6 +10,7 @@ use rustc_ast::tokenstream::TokenTree;
use rustc_ast::{self as ast, AttrStyle, HasAttrs, StmtKind};
use rustc_errors::emitter::stderr_destination;
use rustc_errors::{ColorConfig, DiagCtxtHandle};
use rustc_parse::lexer::StripTokens;
use rustc_parse::new_parser_from_source_str;
use rustc_session::parse::ParseSess;
use rustc_span::edition::{DEFAULT_EDITION, Edition};
@ -468,14 +469,16 @@ fn parse_source(
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
let psess = ParseSess::with_dcx(dcx, sm);
let mut parser = match new_parser_from_source_str(&psess, filename, wrapped_source) {
Ok(p) => p,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
reset_error_count(&psess);
return Err(());
}
};
// Don't strip any tokens; it wouldn't matter anyway because the source is wrapped in a function.
let mut parser =
match new_parser_from_source_str(&psess, filename, wrapped_source, StripTokens::Nothing) {
Ok(p) => p,
Err(errs) => {
errs.into_iter().for_each(|err| err.cancel());
reset_error_count(&psess);
return Err(());
}
};
fn push_to_s(s: &mut String, source: &str, span: rustc_span::Span, prev_span_hi: &mut usize) {
let extra_len = DOCTEST_CODE_WRAPPER.len();

View file

@ -8,6 +8,7 @@ use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
use rustc_errors::emitter::HumanEmitter;
use rustc_errors::{Diag, DiagCtxt};
use rustc_lint::LateContext;
use rustc_parse::lexer::StripTokens;
use rustc_parse::new_parser_from_source_str;
use rustc_parse::parser::ForceCollect;
use rustc_session::parse::ParseSess;
@ -49,13 +50,14 @@ pub fn check(
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let psess = ParseSess::with_dcx(dcx, sm);
let mut parser = match new_parser_from_source_str(&psess, filename, code) {
Ok(p) => p,
Err(errs) => {
errs.into_iter().for_each(Diag::cancel);
return (false, test_attr_spans);
},
};
let mut parser =
match new_parser_from_source_str(&psess, filename, code, StripTokens::ShebangAndFrontmatter) {
Ok(p) => p,
Err(errs) => {
errs.into_iter().for_each(Diag::cancel);
return (false, test_attr_spans);
},
};
let mut relevant_main_found = false;
let mut eligible = true;

View file

@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use rustc_ast::{ast, attr};
use rustc_errors::Diag;
use rustc_parse::lexer::StripTokens;
use rustc_parse::parser::Parser as RawParser;
use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_span::{Span, sym};
@ -64,11 +65,14 @@ impl<'a> ParserBuilder<'a> {
input: Input,
) -> Result<RawParser<'a>, Vec<Diag<'a>>> {
match input {
Input::File(ref file) => new_parser_from_file(psess, file, None),
Input::File(ref file) => {
new_parser_from_file(psess, file, StripTokens::ShebangAndFrontmatter, None)
}
Input::Text(text) => new_parser_from_source_str(
psess,
rustc_span::FileName::Custom("stdin".to_owned()),
text,
StripTokens::ShebangAndFrontmatter,
),
}
}
@ -104,8 +108,12 @@ impl<'a> Parser<'a> {
span: Span,
) -> Result<(ast::AttrVec, ThinVec<Box<ast::Item>>, Span), ParserError> {
let result = catch_unwind(AssertUnwindSafe(|| {
let mut parser =
unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span)));
let mut parser = unwrap_or_emit_fatal(new_parser_from_file(
psess.inner(),
path,
StripTokens::ShebangAndFrontmatter,
Some(span),
));
match parser.parse_mod(exp!(Eof)) {
Ok((a, i, spans)) => Some((a, i, spans.inner_span)),
Err(e) => {

View file

@ -10,7 +10,7 @@ extern crate rustc_span;
use rustc_ast::ast::{AttrKind, Attribute, DUMMY_NODE_ID, Expr};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::node_id::NodeId;
use rustc_ast::token::{self, Token};
use rustc_ast::token;
use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, LazyAttrTokenStream};
use rustc_errors::Diag;
use rustc_parse::parser::Recovery;
@ -23,6 +23,7 @@ pub fn parse_expr(psess: &ParseSess, source_code: &str) -> Option<Box<Expr>> {
psess,
FileName::anon_source_code(source_code),
source_code.to_owned(),
rustc_parse::lexer::StripTokens::Nothing,
));
let mut parser = parser.recovery(Recovery::Forbidden);

View file

@ -16,7 +16,7 @@ extern crate rustc_span;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
use rustc_parse::{lexer::StripTokens, new_parser_from_file, unwrap_or_emit_fatal};
use rustc_session::parse::ParseSess;
use std::path::Path;
@ -34,6 +34,11 @@ fn parse() {
let path = Path::new(file!());
let path = path.canonicalize().unwrap();
let mut parser = unwrap_or_emit_fatal(new_parser_from_file(&psess, &path, None));
let mut parser = unwrap_or_emit_fatal(new_parser_from_file(
&psess,
&path,
StripTokens::ShebangAndFrontmatter,
None,
));
let _ = parser.parse_crate_mod();
}

View file

@ -13,6 +13,6 @@ fn ordering4 < 'a , 'b > ( a : , self , self , self ,
//~| ERROR unexpected `self` parameter in function
//~| ERROR unexpected `self` parameter in function
//~| ERROR `...` must be the last argument of a C-variadic function
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~| ERROR `...` is not supported for non-extern functions
//~| ERROR cannot find type `F` in this scope
}

View file

@ -46,11 +46,13 @@ error: `...` must be the last argument of a C-variadic function
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
error: `...` is not supported for non-extern functions
--> $DIR/issue-86053-1.rs:11:36
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error[E0412]: cannot find type `F` in this scope
--> $DIR/issue-86053-1.rs:11:48

View file

@ -0,0 +1,7 @@
//@ edition: 2021
#![feature(c_variadic)]
#![crate_type = "lib"]
async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
//~^ ERROR functions cannot be both `async` and C-variadic
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds

View file

@ -0,0 +1,19 @@
error: functions cannot be both `async` and C-variadic
--> $DIR/not-async.rs:5:1
|
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
| ^^^^^ `async` because of this ^^^ C-variadic because of this
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
--> $DIR/not-async.rs:5:59
|
LL | async unsafe extern "C" fn cannot_be_async(x: isize, ...) {}
| --------------------------------------------------------- ^^
| |
| opaque type defined here
|
= note: hidden type `{async fn body of cannot_be_async()}` captures lifetime `'_`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View file

@ -53,9 +53,7 @@ extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait {
x
}
extern "cmse-nonsecure-entry" fn static_trait_object(
x: &'static dyn Trait,
) -> &'static dyn Trait {
extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait {
//~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798]
x
}
@ -63,14 +61,12 @@ extern "cmse-nonsecure-entry" fn static_trait_object(
#[repr(transparent)]
struct WrapperTransparent<'a>(&'a dyn Trait);
extern "cmse-nonsecure-entry" fn wrapped_trait_object(
x: WrapperTransparent,
) -> WrapperTransparent {
extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent {
//~^ ERROR return value of `"cmse-nonsecure-entry"` function too large to pass via registers [E0798]
x
}
extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
//~^ ERROR `...` is not supported for `extern "cmse-nonsecure-entry"` functions
//~| ERROR requires `va_list` lang_item
}

View file

@ -1,8 +1,12 @@
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/generics.rs:73:53
error: `...` is not supported for `extern "cmse-nonsecure-entry"` functions
--> $DIR/generics.rs:69:60
|
LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
| ^^^^^^
LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
| ----------------------------- ^^^^^^
| |
| `extern "cmse-nonsecure-entry"` because of this
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error[E0798]: functions with the `"cmse-nonsecure-entry"` ABI cannot contain generics in their type
--> $DIR/generics.rs:30:1
@ -50,28 +54,28 @@ LL | extern "cmse-nonsecure-entry" fn trait_object(x: &dyn Trait) -> &dyn Trait
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers
--> $DIR/generics.rs:58:6
--> $DIR/generics.rs:56:80
|
LL | ) -> &'static dyn Trait {
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
LL | extern "cmse-nonsecure-entry" fn static_trait_object(x: &'static dyn Trait) -> &'static dyn Trait {
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error[E0798]: return value of `"cmse-nonsecure-entry"` function too large to pass via registers
--> $DIR/generics.rs:68:6
--> $DIR/generics.rs:64:81
|
LL | ) -> WrapperTransparent {
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
LL | extern "cmse-nonsecure-entry" fn wrapped_trait_object(x: WrapperTransparent) -> WrapperTransparent {
| ^^^^^^^^^^^^^^^^^^ this type doesn't fit in the available registers
|
= note: functions with the `"cmse-nonsecure-entry"` ABI must pass their result via the available return registers
= note: the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
error: requires `va_list` lang_item
--> $DIR/generics.rs:73:53
--> $DIR/generics.rs:69:60
|
LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
| ^^^^^^
LL | unsafe extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) {
| ^^^^^^
error: aborting due to 9 previous errors

View file

@ -0,0 +1,79 @@
// The purpose of this file is to track the error messages from Pin and DerefMut interacting.
//
// Identical to `pin-deref.rs` except for using unstable `const fn`.
//@ check-fail
#![feature(const_convert)]
#![feature(const_trait_impl)]
use std::ops::DerefMut;
use std::pin::Pin;
struct MyUnpinType {}
impl MyUnpinType {
const fn at_self(&self) {}
const fn at_mut_self(&mut self) {}
}
struct MyPinType(core::marker::PhantomPinned);
impl MyPinType {
const fn at_self(&self) {}
const fn at_mut_self(&mut self) {}
}
const fn call_mut_ref_unpin(mut r_unpin: Pin<&mut MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self();
}
const fn call_ref_unpin(mut r_unpin: Pin<&MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}
const fn call_mut_ref_pin(mut r_pin: Pin<&mut MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}
const fn call_ref_pin(mut r_pin: Pin<&MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}
const fn coerce_unpin_rr<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}
const fn coerce_unpin_rm<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}
const fn coerce_unpin_mr<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}
const fn coerce_unpin_mm<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin
}
const fn coerce_pin_rr<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a MyPinType {
r_pin
}
const fn coerce_pin_rm<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}
const fn coerce_pin_mr<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a MyPinType {
r_pin
}
const fn coerce_pin_mm<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}
fn main() {}

View file

@ -0,0 +1,51 @@
error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
--> $DIR/pin-deref-const.rs:34:5
|
LL | r_unpin.at_mut_self();
| ^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
--> $DIR/pin-deref-const.rs:39:5
|
LL | r_pin.at_mut_self();
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
--> $DIR/pin-deref-const.rs:44:5
|
LL | r_pin.at_mut_self();
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
--> $DIR/pin-deref-const.rs:52:5
|
LL | r_unpin
| ^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
--> $DIR/pin-deref-const.rs:68:5
|
LL | r_pin
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
--> $DIR/pin-deref-const.rs:76:5
|
LL | r_pin
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0596`.

View file

@ -0,0 +1,76 @@
// The purpose of this file is to track the error messages from Pin and DerefMut interacting.
//
// Identical to `pin-deref-const.rs` except for being stable and not using `const fn`.
//@ check-fail
use std::ops::DerefMut;
use std::pin::Pin;
struct MyUnpinType {}
impl MyUnpinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}
struct MyPinType(core::marker::PhantomPinned);
impl MyPinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}
fn call_mut_ref_unpin(mut r_unpin: Pin<&mut MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self();
}
fn call_ref_unpin(mut r_unpin: Pin<&MyUnpinType>) {
r_unpin.at_self();
r_unpin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}
fn call_mut_ref_pin(mut r_pin: Pin<&mut MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}
fn call_ref_pin(mut r_pin: Pin<&MyPinType>) {
r_pin.at_self();
r_pin.at_mut_self(); //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}
fn coerce_unpin_rr<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}
fn coerce_unpin_rm<'a>(mut r_unpin: &'a mut Pin<&MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin //~ ERROR: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
}
fn coerce_unpin_mr<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a MyUnpinType {
r_unpin
}
fn coerce_unpin_mm<'a>(mut r_unpin: &'a mut Pin<&mut MyUnpinType>) -> &'a mut MyUnpinType {
r_unpin
}
fn coerce_pin_rr<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a MyPinType {
r_pin
}
fn coerce_pin_rm<'a>(mut r_pin: &'a mut Pin<&MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
}
fn coerce_pin_mr<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a MyPinType {
r_pin
}
fn coerce_pin_mm<'a>(mut r_pin: &'a mut Pin<&mut MyPinType>) -> &'a mut MyPinType {
r_pin //~ ERROR: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
}
fn main() {}

View file

@ -0,0 +1,51 @@
error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
--> $DIR/pin-deref.rs:31:5
|
LL | r_unpin.at_mut_self();
| ^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
--> $DIR/pin-deref.rs:36:5
|
LL | r_pin.at_mut_self();
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
--> $DIR/pin-deref.rs:41:5
|
LL | r_pin.at_mut_self();
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyUnpinType>` as mutable
--> $DIR/pin-deref.rs:49:5
|
LL | r_unpin
| ^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyUnpinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&MyPinType>` as mutable
--> $DIR/pin-deref.rs:65:5
|
LL | r_pin
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&MyPinType>`
error[E0596]: cannot borrow data in dereference of `Pin<&mut MyPinType>` as mutable
--> $DIR/pin-deref.rs:73:5
|
LL | r_pin
| ^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Pin<&mut MyPinType>`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0596`.

View file

@ -0,0 +1,40 @@
// The purpose of this file is to track the error messages from Pin and DerefMut interacting.
//@ check-fail
use std::ops::DerefMut;
use std::pin::Pin;
struct MyUnpinType {}
impl MyUnpinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}
struct MyPinType(core::marker::PhantomPinned);
impl MyPinType {
fn at_self(&self) {}
fn at_mut_self(&mut self) {}
}
fn impl_deref_mut(_: impl DerefMut) {}
fn unpin_impl_ref(r_unpin: Pin<&MyUnpinType>) {
impl_deref_mut(r_unpin)
//~^ ERROR: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
}
fn unpin_impl_mut(r_unpin: Pin<&mut MyUnpinType>) {
impl_deref_mut(r_unpin)
}
fn pin_impl_ref(r_pin: Pin<&MyPinType>) {
impl_deref_mut(r_pin)
//~^ ERROR: `PhantomPinned` cannot be unpinned
//~| ERROR: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
}
fn pin_impl_mut(r_pin: Pin<&mut MyPinType>) {
impl_deref_mut(r_pin)
//~^ ERROR: `PhantomPinned` cannot be unpinned
}
fn main() {}

View file

@ -0,0 +1,85 @@
error[E0277]: the trait bound `Pin<&MyUnpinType>: DerefMut` is not satisfied
--> $DIR/pin-impl-deref.rs:24:20
|
LL | impl_deref_mut(r_unpin)
| -------------- ^^^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyUnpinType>`
| |
| required by a bound introduced by this call
|
= note: required for `Pin<&MyUnpinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
help: consider mutably borrowing here
|
LL | impl_deref_mut(&mut r_unpin)
| ++++
error[E0277]: the trait bound `Pin<&MyPinType>: DerefMut` is not satisfied
--> $DIR/pin-impl-deref.rs:31:20
|
LL | impl_deref_mut(r_pin)
| -------------- ^^^^^ the trait `DerefMut` is not implemented for `Pin<&MyPinType>`
| |
| required by a bound introduced by this call
|
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
help: consider mutably borrowing here
|
LL | impl_deref_mut(&mut r_pin)
| ++++
error[E0277]: `PhantomPinned` cannot be unpinned
--> $DIR/pin-impl-deref.rs:31:20
|
LL | impl_deref_mut(r_pin)
| -------------- ^^^^^ within `MyPinType`, the trait `Unpin` is not implemented for `PhantomPinned`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required because it appears within the type `MyPinType`
--> $DIR/pin-impl-deref.rs:15:8
|
LL | struct MyPinType(core::marker::PhantomPinned);
| ^^^^^^^^^
= note: required for `Pin<&MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
error[E0277]: `PhantomPinned` cannot be unpinned
--> $DIR/pin-impl-deref.rs:36:20
|
LL | impl_deref_mut(r_pin)
| -------------- ^^^^^ within `MyPinType`, the trait `Unpin` is not implemented for `PhantomPinned`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
note: required because it appears within the type `MyPinType`
--> $DIR/pin-impl-deref.rs:15:8
|
LL | struct MyPinType(core::marker::PhantomPinned);
| ^^^^^^^^^
= note: required for `Pin<&mut MyPinType>` to implement `DerefMut`
note: required by a bound in `impl_deref_mut`
--> $DIR/pin-impl-deref.rs:22:27
|
LL | fn impl_deref_mut(_: impl DerefMut) {}
| ^^^^^^^^ required by this bound in `impl_deref_mut`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -1,10 +1,10 @@
#![crate_type="lib"]
#![crate_type = "lib"]
pub unsafe extern "C" fn test(_: i32, ap: ...) { }
pub unsafe extern "C" fn test(_: i32, ap: ...) {}
//~^ ERROR C-variadic functions are unstable
trait Trait {
unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
//~^ ERROR C-variadic functions are unstable
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~| ERROR associated functions cannot have a C variable argument list
}

View file

@ -1,14 +1,14 @@
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
error: associated functions cannot have a C variable argument list
--> $DIR/feature-gate-c_variadic.rs:7:45
|
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
| ^^^^^^^
error[E0658]: C-variadic functions are unstable
--> $DIR/feature-gate-c_variadic.rs:3:1
|
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information
= help: add `#![feature(c_variadic)]` to the crate attributes to enable
@ -17,8 +17,8 @@ LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { }
error[E0658]: C-variadic functions are unstable
--> $DIR/feature-gate-c_variadic.rs:7:5
|
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #44930 <https://github.com/rust-lang/rust/issues/44930> for more information
= help: add `#![feature(c_variadic)]` to the crate attributes to enable

View file

@ -62,6 +62,11 @@ LL | format!("", 1, 2);
| | |
| | argument never used
| multiple missing formatting specifiers
|
help: format specifiers use curly braces, consider adding 2 format specifiers
|
LL | format!("{}{}", 1, 2);
| ++++
error: argument never used
--> $DIR/ifmt-bad-arg.rs:33:22
@ -102,6 +107,11 @@ LL | format!("", foo=2);
| -- ^ named argument never used
| |
| formatting specifier missing
|
help: format specifiers use curly braces, consider adding a format specifier
|
LL | format!("{}", foo=2);
| ++
error: multiple unused formatting arguments
--> $DIR/ifmt-bad-arg.rs:38:32
@ -111,6 +121,8 @@ LL | format!("{} {}", 1, 2, foo=1, bar=2);
| | |
| | named argument never used
| multiple missing formatting specifiers
|
= note: consider adding 2 format specifiers
error: duplicate argument named `foo`
--> $DIR/ifmt-bad-arg.rs:40:29

View file

@ -0,0 +1,4 @@
---
-
---
1

View file

@ -1,8 +1,20 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro::{Literal, TokenStream};
#[proc_macro]
pub fn check(_: TokenStream) -> TokenStream {
// In the following test cases, the `---` may look like the start of frontmatter but it is not!
// That's because it would be backward incompatible to interpret them as such in the latest
// stable edition. That's not only the case due to the feature gate error but also due to the
// fact that we "eagerly" emit errors on malformed frontmatter.
// issue: <https://github.com/rust-lang/rust/issues/145520>
_ = "---".parse::<TokenStream>();
// Just a sequence of regular Rust punctuation tokens.
assert_eq!(6, "---\n---".parse::<TokenStream>().unwrap().into_iter().count());
// issue: <https://github.com/rust-lang/rust/issues/146132>
assert!("---".parse::<Literal>().is_err());
Default::default()
}

View file

@ -0,0 +1,9 @@
// Check that an expr-ctxt `include` doesn't try to parse frontmatter and instead
// treats it as a regular Rust token sequence.
//@ check-pass
#![expect(double_negations)]
fn main() {
// issue: <https://github.com/rust-lang/rust/issues/145945>
const _: () = assert!(-1 == include!("auxiliary/expr.rs"));
}

View file

@ -0,0 +1,10 @@
// Ensure that in item ctxts we can `include` files that contain frontmatter.
//@ check-pass
#![feature(frontmatter)]
include!("auxiliary/lib.rs");
fn main() {
foo(1);
}

View file

@ -1,12 +0,0 @@
#![feature(frontmatter)]
//@ check-pass
include!("auxiliary/lib.rs");
// auxiliary/lib.rs contains a frontmatter. Ensure that we can use them in an
// `include!` macro.
fn main() {
foo(1);
}

View file

@ -2,10 +2,9 @@
//@ proc-macro: makro.rs
//@ edition: 2021
// Check that a proc-macro doesn't try to parse frontmatter and instead treats
// it as a regular Rust token sequence. See `auxiliary/makro.rs` for details.
makro::check!();
// checks that a proc-macro doesn't know or parse frontmatters at all and instead treats
// it as normal Rust code.
// see auxiliary/makro.rs for how it is tested.
fn main() {}

View file

@ -3,6 +3,7 @@
#![feature(c_variadic)]
async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
//~^ ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
//~^ ERROR functions cannot be both `async` and C-variadic
//~| ERROR hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
fn main() {}

View file

@ -1,3 +1,9 @@
error: functions cannot be both `async` and C-variadic
--> $DIR/note-and-explain-ReVar-124973.rs:5:1
|
LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
| ^^^^^ `async` because of this ^^^ C-variadic because of this
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
--> $DIR/note-and-explain-ReVar-124973.rs:5:73
|
@ -8,6 +14,6 @@ LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, ...) {}
|
= note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_`
error: aborting due to 1 previous error
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0700`.

View file

@ -7,6 +7,11 @@ LL | println!("Test", 123, 456, 789);
| | | argument never used
| | argument never used
| multiple missing formatting specifiers
|
help: format specifiers use curly braces, consider adding 3 format specifiers
|
LL | println!("Test{}{}{}", 123, 456, 789);
| ++++++
error: multiple unused formatting arguments
--> $DIR/format-unused-lables.rs:6:9
@ -19,6 +24,11 @@ LL | 456,
| ^^^ argument never used
LL | 789
| ^^^ argument never used
|
help: format specifiers use curly braces, consider adding 3 format specifiers
|
LL | println!("Test2{}{}{}",
| ++++++
error: named argument never used
--> $DIR/format-unused-lables.rs:11:35
@ -27,6 +37,11 @@ LL | println!("Some stuff", UNUSED="args");
| ------------ ^^^^^^ named argument never used
| |
| formatting specifier missing
|
help: format specifiers use curly braces, consider adding a format specifier
|
LL | println!("Some stuff{}", UNUSED="args");
| ++
error: multiple unused formatting arguments
--> $DIR/format-unused-lables.rs:14:9

View file

@ -4,7 +4,6 @@
fn main() {}
fn foo(_: Bar, ...) -> impl {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~| ERROR cannot find type `Bar` in this scope
unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
//~^ ERROR cannot find type `Bar` in this scope
//~| ERROR at least one trait must be specified

View file

@ -1,21 +1,15 @@
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:16
|
LL | fn foo(_: Bar, ...) -> impl {}
| ^^^
error: at least one trait must be specified
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:24
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:42
|
LL | fn foo(_: Bar, ...) -> impl {}
| ^^^^
LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
| ^^^^
error[E0412]: cannot find type `Bar` in this scope
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:11
--> $DIR/issue-83499-input-output-iteration-ice.rs:7:29
|
LL | fn foo(_: Bar, ...) -> impl {}
| ^^^ not found in this scope
LL | unsafe extern "C" fn foo(_: Bar, ...) -> impl {}
| ^^^ not found in this scope
error: aborting due to 3 previous errors
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0412`.

View file

@ -5,6 +5,11 @@ LL | println!("C", unsafe { &symbol });
| --- ^^^^^^^^^^^^^^^^^^ argument never used
| |
| formatting specifier missing
|
help: format specifiers use curly braces, consider adding a format specifier
|
LL | println!("C{}", unsafe { &symbol });
| ++
error[E0277]: the size for values of type `[i8]` cannot be known at compilation time
--> $DIR/unsized-extern-static.rs:6:5

View file

@ -4,25 +4,28 @@
fn main() {}
fn f1_1(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR `...` is not supported for non-extern functions
fn f1_2(...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR `...` is not supported for non-extern functions
unsafe extern "Rust" fn f1_3(...) {}
//~^ ERROR `...` is not supported for `extern "Rust"` functions
extern "C" fn f2_1(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR functions with a C variable argument list must be unsafe
extern "C" fn f2_2(...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR functions with a C variable argument list must be unsafe
extern "C" fn f2_3(..., x: isize) {}
//~^ ERROR `...` must be the last argument of a C-variadic function
extern "C" fn f3_1(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR functions with a C variable argument list must be unsafe
extern "C" fn f3_2(...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR functions with a C variable argument list must be unsafe
extern "C" fn f3_3(..., x: isize) {}
//~^ ERROR `...` must be the last argument of a C-variadic function
@ -33,12 +36,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {}
const extern "C" fn f4_2(x: isize, ...) {}
//~^ ERROR functions cannot be both `const` and C-variadic
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~| ERROR functions with a C variable argument list must be unsafe
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
const extern "C" fn f4_3(..., x: isize, ...) {}
//~^ ERROR functions cannot be both `const` and C-variadic
//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~| ERROR functions with a C variable argument list must be unsafe
//~| ERROR `...` must be the last argument of a C-variadic function
extern "C" {
@ -50,30 +53,30 @@ struct X;
impl X {
fn i_f1(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn i_f2(...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn i_f3(..., x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
//~| ERROR `...` must be the last argument of a C-variadic function
fn i_f4(..., x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
//~| ERROR `...` must be the last argument of a C-variadic function
const fn i_f5(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
//~| ERROR functions cannot be both `const` and C-variadic
//~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
}
trait T {
fn t_f1(x: isize, ...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn t_f2(x: isize, ...);
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn t_f3(...) {}
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn t_f4(...);
//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
//~^ ERROR associated functions cannot have a C variable argument list
fn t_f5(..., x: isize) {}
//~^ ERROR `...` must be the last argument of a C-variadic function
fn t_f6(..., x: isize);

View file

@ -1,181 +1,225 @@
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:6:19
|
LL | fn f1_1(x: isize, ...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
error: `...` is not supported for non-extern functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:9:9
|
LL | fn f1_2(...) {}
| ^^^
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
error: `...` is not supported for `extern "Rust"` functions
--> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
|
LL | unsafe extern "Rust" fn f1_3(...) {}
| ------------- ^^^
| |
| `extern "Rust"` because of this
|
= help: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:15:30
|
LL | extern "C" fn f2_1(x: isize, ...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "C" fn f2_1(x: isize, ...) {}
| ++++++
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
|
LL | extern "C" fn f2_2(...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "C" fn f2_2(...) {}
| ++++++
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:18:20
--> $DIR/variadic-ffi-semantic-restrictions.rs:21:20
|
LL | extern "C" fn f2_3(..., x: isize) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:21:30
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:24:30
|
LL | extern "C" fn f3_1(x: isize, ...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "C" fn f3_1(x: isize, ...) {}
| ++++++
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:24:20
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
|
LL | extern "C" fn f3_2(...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | unsafe extern "C" fn f3_2(...) {}
| ++++++
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:27:20
--> $DIR/variadic-ffi-semantic-restrictions.rs:30:20
|
LL | extern "C" fn f3_3(..., x: isize) {}
| ^^^
error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:30:1
--> $DIR/variadic-ffi-semantic-restrictions.rs:33:1
|
LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
| ^^^^^ `const` because of this ^^^ C-variadic because of this
error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:34:1
--> $DIR/variadic-ffi-semantic-restrictions.rs:37:1
|
LL | const extern "C" fn f4_2(x: isize, ...) {}
| ^^^^^ `const` because of this ^^^ C-variadic because of this
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
|
LL | const extern "C" fn f4_2(x: isize, ...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | const unsafe extern "C" fn f4_2(x: isize, ...) {}
| ++++++
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:39:26
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:26
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^
error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:39:1
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:1
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^^^ `const` because of this ^^^ C-variadic because of this
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:39:41
error: functions with a C variable argument list must be unsafe
--> $DIR/variadic-ffi-semantic-restrictions.rs:42:41
|
LL | const extern "C" fn f4_3(..., x: isize, ...) {}
| ^^^
|
help: add the `unsafe` keyword to this definition
|
LL | const unsafe extern "C" fn f4_3(..., x: isize, ...) {}
| ++++++
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:45:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:48:13
|
LL | fn e_f2(..., x: isize);
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:52:23
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:55:23
|
LL | fn i_f1(x: isize, ...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:54:13
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:57:13
|
LL | fn i_f2(...) {}
| ^^^
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:56:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
|
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:56:28
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
|
LL | fn i_f3(..., x: isize, ...) {}
| ^^^
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:13
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:59:28
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:28
|
LL | fn i_f4(..., x: isize, ...) {}
| ^^^
error: functions cannot be both `const` and C-variadic
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:5
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:5
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^^^ ^^^ C-variadic because of this
| |
| `const` because of this
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:69:23
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:72:23
|
LL | fn t_f1(x: isize, ...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:71:23
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:74:23
|
LL | fn t_f2(x: isize, ...);
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:76:13
|
LL | fn t_f3(...) {}
| ^^^
error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention
--> $DIR/variadic-ffi-semantic-restrictions.rs:75:13
error: associated functions cannot have a C variable argument list
--> $DIR/variadic-ffi-semantic-restrictions.rs:78:13
|
LL | fn t_f4(...);
| ^^^
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:77:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:80:13
|
LL | fn t_f5(..., x: isize) {}
| ^^^
error: `...` must be the last argument of a C-variadic function
--> $DIR/variadic-ffi-semantic-restrictions.rs:79:13
--> $DIR/variadic-ffi-semantic-restrictions.rs:82:13
|
LL | fn t_f6(..., x: isize);
| ^^^
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
--> $DIR/variadic-ffi-semantic-restrictions.rs:30:43
--> $DIR/variadic-ffi-semantic-restrictions.rs:33:43
|
LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
| ^^^ - value is dropped here
@ -183,7 +227,7 @@ LL | const unsafe extern "C" fn f4_1(x: isize, ...) {}
| the destructor for this type cannot be evaluated in constant functions
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
--> $DIR/variadic-ffi-semantic-restrictions.rs:34:36
--> $DIR/variadic-ffi-semantic-restrictions.rs:37:36
|
LL | const extern "C" fn f4_2(x: isize, ...) {}
| ^^^ - value is dropped here
@ -191,13 +235,13 @@ LL | const extern "C" fn f4_2(x: isize, ...) {}
| the destructor for this type cannot be evaluated in constant functions
error[E0493]: destructor of `VaListImpl<'_>` cannot be evaluated at compile-time
--> $DIR/variadic-ffi-semantic-restrictions.rs:62:29
--> $DIR/variadic-ffi-semantic-restrictions.rs:65:29
|
LL | const fn i_f5(x: isize, ...) {}
| ^^^ - value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions
error: aborting due to 32 previous errors
error: aborting due to 33 previous errors
For more information about this error, try `rustc --explain E0493`.

View file

@ -0,0 +1,35 @@
fn no_format_specifier_two_unused_args() {
println!("Hello", "World");
//~^ ERROR argument never used
//~| NOTE formatting specifier missing
//~| NOTE argument never used
//~| HELP format specifiers use curly braces, consider adding a format specifier
}
fn no_format_specifier_multiple_unused_args() {
println!("list: ", 1, 2, 3);
//~^ ERROR multiple unused formatting arguments
//~| NOTE multiple missing formatting specifiers
//~| NOTE argument never used
//~| NOTE argument never used
//~| NOTE argument never used
//~| HELP format specifiers use curly braces, consider adding 3 format specifiers
}
fn missing_format_specifiers_one_unused_arg() {
println!("list: {}, {}", 1, 2, 3);
//~^ ERROR argument never used
//~| NOTE formatting specifier missing
//~| NOTE argument never used
}
fn missing_format_specifiers_multiple_unused_args() {
println!("list: {}", 1, 2, 3);
//~^ ERROR multiple unused formatting arguments
//~| NOTE multiple missing formatting specifiers
//~| NOTE argument never used
//~| NOTE argument never used
//~| NOTE consider adding 2 format specifiers
}
fn main() { }

View file

@ -0,0 +1,49 @@
error: argument never used
--> $DIR/missing-format-specifiers-issue-68293.rs:2:23
|
LL | println!("Hello", "World");
| ------- ^^^^^^^ argument never used
| |
| formatting specifier missing
|
help: format specifiers use curly braces, consider adding a format specifier
|
LL | println!("Hello{}", "World");
| ++
error: multiple unused formatting arguments
--> $DIR/missing-format-specifiers-issue-68293.rs:10:24
|
LL | println!("list: ", 1, 2, 3);
| -------- ^ ^ ^ argument never used
| | | |
| | | argument never used
| | argument never used
| multiple missing formatting specifiers
|
help: format specifiers use curly braces, consider adding 3 format specifiers
|
LL | println!("list: {}{}{}", 1, 2, 3);
| ++++++
error: argument never used
--> $DIR/missing-format-specifiers-issue-68293.rs:20:36
|
LL | println!("list: {}, {}", 1, 2, 3);
| -------------- ^ argument never used
| |
| formatting specifier missing
error: multiple unused formatting arguments
--> $DIR/missing-format-specifiers-issue-68293.rs:27:29
|
LL | println!("list: {}", 1, 2, 3);
| ---------- ^ ^ argument never used
| | |
| | argument never used
| multiple missing formatting specifiers
|
= note: consider adding 2 format specifiers
error: aborting due to 4 previous errors

View file

@ -21,6 +21,20 @@ fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
fn baz<T>() where T: Iterator<Item: ?Trait1> {}
//~^ ERROR this relaxed bound is not permitted here
struct S1<T>(T);
impl<T> S1<T> {
fn f() where T: ?Trait1 {}
//~^ ERROR this relaxed bound is not permitted here
}
trait Trait5<'a> {}
struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
//~^ ERROR this relaxed bound is not permitted here
//~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
struct S;
impl !Trait2 for S {}

View file

@ -1,3 +1,27 @@
error: this relaxed bound is not permitted here
--> $DIR/more_maybe_bounds.rs:23:37
|
LL | fn baz<T>() where T: Iterator<Item: ?Trait1> {}
| ^^^^^^^
|
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
error: this relaxed bound is not permitted here
--> $DIR/more_maybe_bounds.rs:29:21
|
LL | fn f() where T: ?Trait1 {}
| ^^^^^^^
|
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
error: this relaxed bound is not permitted here
--> $DIR/more_maybe_bounds.rs:35:34
|
LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
| ^^^^^^^^^^^
|
= note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/more_maybe_bounds.rs:17:20
|
@ -16,5 +40,11 @@ error: bound modifier `?` can only be applied to default traits like `Sized`
LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
| ^^^^^^^
error: aborting due to 3 previous errors
error: bound modifier `?` can only be applied to default traits like `Sized`
--> $DIR/more_maybe_bounds.rs:35:34
|
LL | struct S2<T>(T) where for<'a> T: ?Trait5<'a>;
| ^^^^^^^^^^^
error: aborting due to 7 previous errors

View file

@ -1,31 +0,0 @@
//@ check-pass
//@ compile-flags: -Zexperimental-default-bounds
#![feature(auto_traits, lang_items, no_core, rustc_attrs, trait_alias)]
#![no_std]
#![no_core]
#[lang = "pointee_sized"]
trait PointeeSized {}
#[lang = "meta_sized"]
trait MetaSized: PointeeSized {}
#[lang = "sized"]
trait Sized: MetaSized {}
#[lang = "default_trait1"]
auto trait DefaultTrait1 {}
#[lang = "default_trait2"]
auto trait DefaultTrait2 {}
trait Trait<Rhs: ?Sized = Self> {}
trait Trait1 : Trait {}
trait Trait2 {
type Type;
}
trait Trait3<T> = Trait2<Type = T>;
fn main() {}

View file

@ -13,32 +13,37 @@
#![no_core]
#[lang = "pointee_sized"]
trait PointeeSized {}
trait PointeeSized: ?Leak {}
#[lang = "meta_sized"]
trait MetaSized: PointeeSized {}
trait MetaSized: PointeeSized + ?Leak {}
#[lang = "sized"]
trait Sized: MetaSized {}
trait Sized: MetaSized + ?Leak {}
#[lang = "copy"]
pub trait Copy {}
pub trait Copy: ?Leak {}
impl<'a, T: ?Sized> Copy for &'a T {}
#[lang = "legacy_receiver"]
trait Receiver {}
trait Receiver: ?Leak {}
impl<T: ?Sized + ?Leak> Receiver for &T {}
impl<T: ?Sized + ?Leak> Receiver for &mut T {}
#[lang = "unsize"]
trait Unsize<T: ?Sized + ?Leak> {}
trait Unsize<T: ?Sized + ?Leak>: ?Leak {}
#[lang = "coerce_unsized"]
trait CoerceUnsized<T: ?Leak + ?Sized> {}
trait CoerceUnsized<T: ?Leak + ?Sized>: ?Leak {}
impl<'a, 'b: 'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> CoerceUnsized<&'a U> for &'b T {}
// Omit `T: ?Leak` and `U: ?Leak`.
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'b mut T {}
#[lang = "dispatch_from_dyn"]
trait DispatchFromDyn<T: ?Leak> {}
trait DispatchFromDyn<T: ?Leak>: ?Leak {}
impl<'a, T: ?Sized + ?Leak + Unsize<U>, U: ?Sized + ?Leak> DispatchFromDyn<&'a U> for &'a T {}
// Omit `T: ?Leak` and `U: ?Leak`.
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
#[lang = "default_trait1"]
auto trait Leak {}
@ -47,25 +52,52 @@ struct NonLeakS;
impl !Leak for NonLeakS {}
struct LeakS;
trait Trait {
fn leak_foo(&self) {}
fn maybe_leak_foo(&self) where Self: ?Leak {}
fn bounds_check() {
trait LeakTr {}
trait MaybeLeakTr: ?Leak {}
impl MaybeLeakTr for NonLeakS {}
impl LeakTr for LeakS {}
impl MaybeLeakTr for LeakS {}
let _: &dyn LeakTr = &NonLeakS;
//~^ ERROR the trait bound `NonLeakS: bounds_check::LeakTr` is not satisfied
let _: &dyn LeakTr = &LeakS;
let _: &(dyn LeakTr + ?Leak) = &NonLeakS;
let _: &(dyn LeakTr + ?Leak) = &LeakS;
let _: &dyn MaybeLeakTr = &NonLeakS;
let _: &dyn MaybeLeakTr = &LeakS;
}
impl Trait for NonLeakS {}
impl Trait for LeakS {}
fn dyn_compat_check() {
trait DynCompatCheck1: ?Leak {
fn foo(&self) {}
}
trait DynCompatCheck2: ?Leak {
fn mut_foo(&mut self) {}
}
impl DynCompatCheck1 for NonLeakS {}
impl DynCompatCheck2 for NonLeakS {}
let _: &(dyn DynCompatCheck1 + ?Leak) = &NonLeakS;
// There is no `?Leak` bound on corresponding `DispatchFromDyn` impl.
let _: &dyn DynCompatCheck2 = &NonLeakS;
//~^ ERROR the trait `DynCompatCheck2` is not dyn compatible
}
fn args_check() {
trait LeakTr {}
fn main() {
let _: &dyn Trait = &NonLeakS;
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
let _: &dyn Trait = &LeakS;
let _: &(dyn Trait + ?Leak) = &LeakS;
let x: &(dyn Trait + ?Leak) = &NonLeakS;
x.leak_foo();
//~^ ERROR the trait bound `dyn Trait: Leak` is not satisfied
x.maybe_leak_foo();
// Ensure that we validate the generic args of relaxed bounds in trait object types.
let _: dyn Trait + ?Leak<(), Undefined = ()>;
let _: dyn LeakTr + ?Leak<(), Undefined = ()>;
//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
//~| ERROR associated type `Undefined` not found for `Leak`
}
fn main() {}

View file

@ -1,49 +1,57 @@
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
--> $DIR/maybe-bounds-in-dyn-traits.rs:59:25
error[E0277]: the trait bound `NonLeakS: bounds_check::LeakTr` is not satisfied
--> $DIR/maybe-bounds-in-dyn-traits.rs:65:26
|
LL | let _: &dyn Trait = &NonLeakS;
| ^^^^^^^^^ unsatisfied trait bound
LL | let _: &dyn LeakTr = &NonLeakS;
| ^^^^^^^^^ unsatisfied trait bound
|
help: the trait `Leak` is not implemented for `NonLeakS`
--> $DIR/maybe-bounds-in-dyn-traits.rs:46:1
help: the trait `bounds_check::LeakTr` is not implemented for `NonLeakS`
--> $DIR/maybe-bounds-in-dyn-traits.rs:51:1
|
LL | struct NonLeakS;
| ^^^^^^^^^^^^^^^
= note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak`
= help: the trait `bounds_check::LeakTr` is implemented for `LeakS`
= note: required for the cast from `&NonLeakS` to `&dyn bounds_check::LeakTr + Leak`
error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied
--> $DIR/maybe-bounds-in-dyn-traits.rs:64:7
error[E0038]: the trait `DynCompatCheck2` is not dyn compatible
--> $DIR/maybe-bounds-in-dyn-traits.rs:90:17
|
LL | x.leak_foo();
| ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait`
LL | fn mut_foo(&mut self) {}
| --------- help: consider changing method `mut_foo`'s `self` parameter to be `&self`: `&Self`
...
LL | let _: &dyn DynCompatCheck2 = &NonLeakS;
| ^^^^^^^^^^^^^^^ `DynCompatCheck2` is not dyn compatible
|
note: required by a bound in `Trait::leak_foo`
--> $DIR/maybe-bounds-in-dyn-traits.rs:51:5
note: for a trait to be dyn compatible it needs to allow building a vtable
for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
--> $DIR/maybe-bounds-in-dyn-traits.rs:82:20
|
LL | fn leak_foo(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
LL | trait DynCompatCheck2: ?Leak {
| --------------- this trait is not dyn compatible...
LL | fn mut_foo(&mut self) {}
| ^^^^^^^^^ ...because method `mut_foo`'s `self` parameter cannot be dispatched on
= help: only type `NonLeakS` implements `DynCompatCheck2`; consider using it directly instead.
error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/maybe-bounds-in-dyn-traits.rs:68:25
--> $DIR/maybe-bounds-in-dyn-traits.rs:98:26
|
LL | let _: dyn Trait + ?Leak<(), Undefined = ()>;
| ^^^^-------------------- help: remove the unnecessary generics
| |
| expected 0 generic arguments
LL | let _: dyn LeakTr + ?Leak<(), Undefined = ()>;
| ^^^^-------------------- help: remove the unnecessary generics
| |
| expected 0 generic arguments
|
note: trait defined here, with 0 generic parameters
--> $DIR/maybe-bounds-in-dyn-traits.rs:44:12
--> $DIR/maybe-bounds-in-dyn-traits.rs:49:12
|
LL | auto trait Leak {}
| ^^^^
error[E0220]: associated type `Undefined` not found for `Leak`
--> $DIR/maybe-bounds-in-dyn-traits.rs:68:34
--> $DIR/maybe-bounds-in-dyn-traits.rs:98:35
|
LL | let _: dyn Trait + ?Leak<(), Undefined = ()>;
| ^^^^^^^^^ associated type `Undefined` not found
LL | let _: dyn LeakTr + ?Leak<(), Undefined = ()>;
| ^^^^^^^^^ associated type `Undefined` not found
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0107, E0220, E0277.
For more information about an error, try `rustc --explain E0107`.
Some errors have detailed explanations: E0038, E0107, E0220, E0277.
For more information about an error, try `rustc --explain E0038`.

View file

@ -14,18 +14,22 @@
#![no_std]
#![no_core]
#[lang = "copy"]
pub trait Copy: ?Leak {}
#[lang = "pointee_sized"]
trait PointeeSized {}
trait PointeeSized: ?Leak {}
#[lang = "meta_sized"]
trait MetaSized: PointeeSized {}
trait MetaSized: PointeeSized + ?Leak {}
#[lang = "sized"]
trait Sized: MetaSized {}
trait Sized: MetaSized + ?Leak {}
#[lang = "legacy_receiver"]
trait LegacyReceiver {}
trait LegacyReceiver: ?Leak {}
impl<T: ?Sized + ?Leak> LegacyReceiver for &T {}
// Omit `T: ?Leak`.
impl<T: ?Sized> LegacyReceiver for &mut T {}
#[lang = "default_trait1"]
@ -38,83 +42,40 @@ struct LeakS;
mod supertraits {
use crate::*;
trait MaybeLeakT1: ?Leak {}
trait MaybeLeakT2 where Self: ?Leak {}
trait MaybeLeak: ?Leak {}
impl MaybeLeak for NonLeakS {}
impl MaybeLeakT1 for NonLeakS {}
impl MaybeLeakT2 for NonLeakS {}
trait LeakT {}
impl LeakT for NonLeakS {}
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
}
mod maybe_self_assoc_type {
mod assoc_type_maybe_bounds {
use crate::*;
trait TestBase1<T: ?Sized> {}
trait TestBase2<T: ?Leak + ?Sized> {}
trait Test1<T> {
type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
//~^ ERROR the trait bound `Self: Leak` is not satisfied
type LeakSelf: TestBase1<Self>;
}
trait Test2<T> {
type MaybeLeakSelf: TestBase2<Self> where Self: ?Leak;
type LeakSelf: TestBase2<Self>;
}
trait Test3 {
trait Test1 {
type Leak1 = LeakS;
type Leak2 = NonLeakS;
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
}
trait Test4 {
trait Test2 {
type MaybeLeak1: ?Leak = LeakS;
type MaybeLeak2: ?Leak = NonLeakS;
}
trait Test5: ?Leak {
// ok, because assoc types have implicit where Self: Leak
type MaybeLeakSelf1: TestBase1<Self>;
type MaybeLeakSelf2: TestBase2<Self>;
}
}
mod maybe_self_assoc_const {
use crate::*;
const fn size_of<T: ?Sized>() -> usize {
0
}
trait Trait {
const CLeak: usize = size_of::<Self>();
const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
//~^ ERROR the trait bound `Self: Leak` is not satisfied
}
}
mod methods {
use crate::*;
trait Trait {
fn leak_foo(&self) {}
fn maybe_leak_foo(&self) where Self: ?Leak {}
fn mut_leak_foo(&mut self) {}
// there is no relax bound on corresponding Receiver impl
fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
//~^ ERROR `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types`
trait ReceiveCheck1: ?Leak {
fn foo(&self) {}
}
impl Trait for NonLeakS {}
impl Trait for LeakS {}
fn foo() {
LeakS.leak_foo();
LeakS.maybe_leak_foo();
NonLeakS.leak_foo();
//~^ ERROR the trait bound `NonLeakS: Leak` is not satisfied
NonLeakS.maybe_leak_foo();
trait ReceiveCheck2: ?Leak {
// There is no `?Leak` bound on corresponding `LegacyReceiver` impl.
fn mut_foo(&mut self) {}
//~^ ERROR `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types`
}
}

View file

@ -1,81 +1,49 @@
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
--> $DIR/maybe-bounds-in-traits.rs:67:22
--> $DIR/maybe-bounds-in-traits.rs:49:20
|
LL | impl LeakT for NonLeakS {}
| ^^^^^^^^ unsatisfied trait bound
|
help: the trait `Leak` is not implemented for `NonLeakS`
--> $DIR/maybe-bounds-in-traits.rs:38:1
|
LL | struct NonLeakS;
| ^^^^^^^^^^^^^^^
note: required by a bound in `LeakT`
--> $DIR/maybe-bounds-in-traits.rs:48:5
|
LL | trait LeakT {}
| ^^^^^^^^^^^^^^ required by this bound in `LeakT`
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
--> $DIR/maybe-bounds-in-traits.rs:58:22
|
LL | type Leak2 = NonLeakS;
| ^^^^^^^^ unsatisfied trait bound
|
help: the trait `Leak` is not implemented for `NonLeakS`
--> $DIR/maybe-bounds-in-traits.rs:34:1
--> $DIR/maybe-bounds-in-traits.rs:38:1
|
LL | struct NonLeakS;
| ^^^^^^^^^^^^^^^
note: required by a bound in `Test3::Leak2`
--> $DIR/maybe-bounds-in-traits.rs:67:9
note: required by a bound in `Test1::Leak2`
--> $DIR/maybe-bounds-in-traits.rs:58:9
|
LL | type Leak2 = NonLeakS;
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2`
error[E0277]: the trait bound `Self: Leak` is not satisfied
--> $DIR/maybe-bounds-in-traits.rs:55:29
|
LL | type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
| ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self`
|
note: required by a bound in `TestBase1`
--> $DIR/maybe-bounds-in-traits.rs:51:21
|
LL | trait TestBase1<T: ?Sized> {}
| ^ required by this bound in `TestBase1`
help: consider further restricting `Self`
|
LL | trait Test1<T>: Leak {
| ++++++
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test1::Leak2`
error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
--> $DIR/maybe-bounds-in-traits.rs:105:31
--> $DIR/maybe-bounds-in-traits.rs:77:20
|
LL | fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
| ^^^^^^^^^
LL | fn mut_foo(&mut self) {}
| ^^^^^^^^^
|
= note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
= help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
error[E0277]: the trait bound `Self: Leak` is not satisfied
--> $DIR/maybe-bounds-in-traits.rs:92:43
|
LL | const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
| ^^^^ the trait `Leak` is not implemented for `Self`
|
note: required by a bound in `size_of`
--> $DIR/maybe-bounds-in-traits.rs:86:22
|
LL | const fn size_of<T: ?Sized>() -> usize {
| ^ required by this bound in `size_of`
help: consider further restricting `Self`
|
LL | trait Trait: Leak {
| ++++++
error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
--> $DIR/maybe-bounds-in-traits.rs:115:18
|
LL | NonLeakS.leak_foo();
| ^^^^^^^^ unsatisfied trait bound
|
help: the trait `Leak` is not implemented for `NonLeakS`
--> $DIR/maybe-bounds-in-traits.rs:34:1
|
LL | struct NonLeakS;
| ^^^^^^^^^^^^^^^
note: required by a bound in `methods::Trait::leak_foo`
--> $DIR/maybe-bounds-in-traits.rs:101:9
|
LL | fn leak_foo(&self) {}
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
error: aborting due to 5 previous errors
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0277, E0658.
For more information about an error, try `rustc --explain E0277`.