Auto merge of #101225 - matthiaskrgr:rollup-9s1chas, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #100970 (Allow deriving multipart suggestions)
 - #100984 (Reinstate preloading of some dll imports)
 - #101011 (Use getentropy when possible on all Apple platforms)
 - #101025 (Add tier-3 support for powerpc64 and riscv64 openbsd)
 - #101049 (Remove span fatal from ast lowering)
 - #101100 (Make call suggestions more general and more accurate)
 - #101171 (Fix UB from misalignment and provenance widening in `std::sys::windows`)
 - #101185 (Tweak `WellFormedLoc`s a bit)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-31 07:57:09 +00:00
commit 12e4fd0755
69 changed files with 1652 additions and 935 deletions

View File

@ -327,3 +327,10 @@ pub struct ArbitraryExpressionInPattern {
#[primary_span]
pub span: Span,
}
#[derive(SessionDiagnostic, Clone, Copy)]
#[diag(ast_lowering::inclusive_range_with_no_end)]
pub struct InclusiveRangeWithNoEnd {
#[primary_span]
pub span: Span,
}

View File

@ -1,8 +1,8 @@
use super::errors::{
AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
GeneratorTooManyParameters, NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError,
UnderscoreExprLhsAssign,
GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure,
RustcBoxAttributeError, UnderscoreExprLhsAssign,
};
use super::ResolverAstLoweringExt;
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
@ -1264,7 +1264,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(Some(..), Some(..), Closed) => unreachable!(),
(_, None, Closed) => self.diagnostic().span_fatal(span, "inclusive range with no end"),
(start, None, Closed) => {
self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span });
match start {
Some(..) => hir::LangItem::RangeFrom,
None => hir::LangItem::RangeFull,
}
}
};
let fields = self.arena.alloc_from_iter(

View File

@ -36,6 +36,8 @@
#![feature(never_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
extern crate tracing;

View File

@ -129,3 +129,5 @@ ast_lowering_not_supported_for_lifetime_binder_async_closure =
ast_lowering_arbitrary_expression_in_pattern =
arbitrary expressions aren't allowed in patterns
ast_lowering_inclusive_range_with_no_end = inclusive range with no end

View File

@ -686,19 +686,12 @@ impl Diagnostic {
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
assert!(!suggestion.is_empty());
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: suggestion
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect(),
}],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style: SuggestionStyle::CompletelyHidden,
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
});
self
SuggestionStyle::CompletelyHidden,
)
}
/// Prints out a message with a suggested edit of the code.

View File

@ -1249,9 +1249,13 @@ impl HandlerInner {
}
fn treat_err_as_bug(&self) -> bool {
self.flags
.treat_err_as_bug
.map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
self.flags.treat_err_as_bug.map_or(false, |c| {
self.err_count()
+ self.lint_err_count
+ self.delayed_span_bugs.len()
+ self.delayed_good_path_bugs.len()
>= c.get()
})
}
fn print_error_count(&mut self, registry: &Registry) {
@ -1407,7 +1411,14 @@ impl HandlerInner {
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
if self.flags.treat_err_as_bug.map_or(false, |c| {
self.err_count()
+ self.lint_err_count
+ self.delayed_span_bugs.len()
+ self.delayed_good_path_bugs.len()
+ 1
>= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg);
}

View File

@ -41,7 +41,8 @@ macro_rules! pluralize {
/// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion
/// to determine whether it should be automatically applied or if the user should be consulted
/// before applying the suggestion.
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, Hash, Encodable, Decodable, Serialize, Deserialize)]
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Applicability {
/// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
/// This suggestion should be automatically applied.

View File

@ -342,10 +342,10 @@ fn main() {
};
// RISC-V GCC erroneously requires libatomic for sub-word
// atomic operations. FreeBSD uses Clang as its system
// atomic operations. Some BSD uses Clang as its system
// compiler and provides no libatomic in its base system so
// does not want this.
if !target.contains("freebsd") && target.starts_with("riscv") {
if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd") {
println!("cargo:rustc-link-lib=atomic");
}

View File

@ -12,7 +12,7 @@ use quote::{format_ident, quote};
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use syn::{parse_quote, spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path};
use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
/// Which kind of suggestion is being created?
@ -28,8 +28,41 @@ enum SubdiagnosticSuggestionKind {
Verbose,
}
impl FromStr for SubdiagnosticSuggestionKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"" => Ok(SubdiagnosticSuggestionKind::Normal),
"_short" => Ok(SubdiagnosticSuggestionKind::Short),
"_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden),
"_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose),
_ => Err(()),
}
}
}
impl SubdiagnosticSuggestionKind {
pub fn to_suggestion_style(&self) -> TokenStream {
match self {
SubdiagnosticSuggestionKind::Normal => {
quote! { rustc_errors::SuggestionStyle::ShowCode }
}
SubdiagnosticSuggestionKind::Short => {
quote! { rustc_errors::SuggestionStyle::HideCodeInline }
}
SubdiagnosticSuggestionKind::Hidden => {
quote! { rustc_errors::SuggestionStyle::HideCodeAlways }
}
SubdiagnosticSuggestionKind::Verbose => {
quote! { rustc_errors::SuggestionStyle::ShowAlways }
}
}
}
}
/// Which kind of subdiagnostic is being created from a variant?
#[derive(Clone, Copy)]
#[derive(Clone)]
enum SubdiagnosticKind {
/// `#[label(...)]`
Label,
@ -40,31 +73,9 @@ enum SubdiagnosticKind {
/// `#[warning(...)]`
Warn,
/// `#[suggestion{,_short,_hidden,_verbose}]`
Suggestion(SubdiagnosticSuggestionKind),
}
impl FromStr for SubdiagnosticKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"label" => Ok(SubdiagnosticKind::Label),
"note" => Ok(SubdiagnosticKind::Note),
"help" => Ok(SubdiagnosticKind::Help),
"warning" => Ok(SubdiagnosticKind::Warn),
"suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)),
"suggestion_short" => {
Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short))
}
"suggestion_hidden" => {
Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden))
}
"suggestion_verbose" => {
Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose))
}
_ => Err(()),
}
}
Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream },
/// `#[multipart_suggestion{,_short,_hidden,_verbose}]`
MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind },
}
impl quote::IdentFragment for SubdiagnosticKind {
@ -74,17 +85,9 @@ impl quote::IdentFragment for SubdiagnosticKind {
SubdiagnosticKind::Note => write!(f, "note"),
SubdiagnosticKind::Help => write!(f, "help"),
SubdiagnosticKind::Warn => write!(f, "warn"),
SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => {
write!(f, "suggestion")
}
SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => {
write!(f, "suggestion_short")
}
SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => {
write!(f, "suggestion_hidden")
}
SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => {
write!(f, "suggestion_verbose")
SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"),
SubdiagnosticKind::MultipartSuggestion { .. } => {
write!(f, "multipart_suggestion_with_style")
}
}
}
@ -148,11 +151,9 @@ impl<'a> SessionSubdiagnosticDerive<'a> {
variant,
span,
fields: fields_map,
kind: None,
slug: None,
code: None,
span_field: None,
applicability: None,
has_suggestion_parts: false,
};
builder.into_tokens().unwrap_or_else(|v| v.to_compile_error())
});
@ -193,21 +194,15 @@ struct SessionSubdiagnosticDeriveBuilder<'a> {
/// derive builder.
fields: HashMap<String, TokenStream>,
/// Subdiagnostic kind of the type/variant.
kind: Option<(SubdiagnosticKind, proc_macro::Span)>,
/// Slug of the subdiagnostic - corresponds to the Fluent identifier for the message - from the
/// `#[kind(slug)]` attribute on the type or variant.
slug: Option<(Path, proc_macro::Span)>,
/// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]`
/// attribute on the type or variant.
code: Option<(TokenStream, proc_macro::Span)>,
/// Identifier for the binding to the `#[primary_span]` field.
span_field: Option<(proc_macro2::Ident, proc_macro::Span)>,
/// If a suggestion, the identifier for the binding to the `#[applicability]` field or a
/// `rustc_errors::Applicability::*` variant directly.
applicability: Option<(TokenStream, proc_macro::Span)>,
/// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error
/// during finalization if still `false`.
has_suggestion_parts: bool,
}
impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
@ -217,7 +212,11 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
}
impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
fn identify_kind(
&mut self,
) -> Result<Option<(SubdiagnosticKind, Path)>, DiagnosticDeriveError> {
let mut kind_slug = None;
for attr in self.variant.ast().attrs {
let span = attr.span().unwrap();
@ -225,116 +224,121 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
let name = name.as_str();
let meta = attr.parse_meta()?;
let kind = match meta {
Meta::List(MetaList { ref nested, .. }) => {
let mut nested_iter = nested.into_iter();
if let Some(nested_attr) = nested_iter.next() {
match nested_attr {
NestedMeta::Meta(Meta::Path(path)) => {
self.slug.set_once((path.clone(), span));
}
NestedMeta::Meta(meta @ Meta::NameValue(_))
if matches!(
meta.path().segments.last().unwrap().ident.to_string().as_str(),
"code" | "applicability"
) =>
{
// don't error for valid follow-up attributes
}
nested_attr => {
throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help(
"first argument of the attribute should be the diagnostic \
slug",
)
})
}
};
}
for nested_attr in nested_iter {
let meta = match nested_attr {
NestedMeta::Meta(ref meta) => meta,
_ => throw_invalid_nested_attr!(attr, &nested_attr),
};
let span = meta.span().unwrap();
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
let nested_name = nested_name.as_str();
match meta {
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
match nested_name {
"code" => {
let formatted_str = self.build_format(&s.value(), s.span());
self.code.set_once((formatted_str, span));
}
"applicability" => {
let value = match Applicability::from_str(&s.value()) {
Ok(v) => v,
Err(()) => {
span_err(span, "invalid applicability").emit();
Applicability::Unspecified
}
};
self.applicability.set_once((quote! { #value }, span));
}
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help(
"only `code` and `applicability` are valid nested \
attributes",
)
}),
}
}
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
if matches!(meta, Meta::Path(_)) {
diag.help(
"a diagnostic slug must be the first argument to the \
attribute",
)
} else {
diag
}
}),
}
}
let Ok(kind) = SubdiagnosticKind::from_str(name) else {
throw_invalid_attr!(attr, &meta)
};
kind
}
_ => throw_invalid_attr!(attr, &meta),
let Meta::List(MetaList { ref nested, .. }) = meta else {
throw_invalid_attr!(attr, &meta);
};
if matches!(
kind,
SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
) && self.code.is_some()
{
throw_span_err!(
span,
&format!("`code` is not a valid nested attribute of a `{}` attribute", name)
);
let mut kind = match name {
"label" => SubdiagnosticKind::Label,
"note" => SubdiagnosticKind::Note,
"help" => SubdiagnosticKind::Help,
"warning" => SubdiagnosticKind::Warn,
_ => {
if let Some(suggestion_kind) =
name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
{
SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() }
} else if let Some(suggestion_kind) =
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
{
SubdiagnosticKind::MultipartSuggestion { suggestion_kind }
} else {
throw_invalid_attr!(attr, &meta);
}
}
};
let mut slug = None;
let mut code = None;
let mut nested_iter = nested.into_iter();
if let Some(nested_attr) = nested_iter.next() {
match nested_attr {
NestedMeta::Meta(Meta::Path(path)) => {
slug.set_once((path.clone(), span));
}
NestedMeta::Meta(meta @ Meta::NameValue(_))
if matches!(
meta.path().segments.last().unwrap().ident.to_string().as_str(),
"code" | "applicability"
) =>
{
// Don't error for valid follow-up attributes.
}
nested_attr => {
throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help(
"first argument of the attribute should be the diagnostic \
slug",
)
})
}
};
}
if matches!(
kind,
SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note
) && self.applicability.is_some()
{
throw_span_err!(
span,
&format!(
"`applicability` is not a valid nested attribute of a `{}` attribute",
name
)
);
for nested_attr in nested_iter {
let meta = match nested_attr {
NestedMeta::Meta(ref meta) => meta,
_ => throw_invalid_nested_attr!(attr, &nested_attr),
};
let span = meta.span().unwrap();
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
let nested_name = nested_name.as_str();
let value = match meta {
Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value,
Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help("a diagnostic slug must be the first argument to the attribute")
}),
_ => throw_invalid_nested_attr!(attr, &nested_attr),
};
match nested_name {
"code" => {
if matches!(kind, SubdiagnosticKind::Suggestion { .. }) {
let formatted_str = self.build_format(&value.value(), value.span());
code.set_once((formatted_str, span));
} else {
span_err(
span,
&format!(
"`code` is not a valid nested attribute of a `{}` attribute",
name
),
)
.emit();
}
}
"applicability" => {
if matches!(
kind,
SubdiagnosticKind::Suggestion { .. }
| SubdiagnosticKind::MultipartSuggestion { .. }
) {
let value =
Applicability::from_str(&value.value()).unwrap_or_else(|()| {
span_err(span, "invalid applicability").emit();
Applicability::Unspecified
});
self.applicability.set_once((quote! { #value }, span));
} else {
span_err(
span,
&format!(
"`applicability` is not a valid nested attribute of a `{}` attribute",
name
)
).emit();
}
}
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help("only `code` and `applicability` are valid nested attributes")
}),
}
}
if self.slug.is_none() {
let Some((slug, _)) = slug else {
throw_span_err!(
span,
&format!(
@ -342,150 +346,338 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
name
)
);
};
match kind {
SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => {
let Some((code, _)) = code else {
throw_span_err!(span, "suggestion without `code = \"...\"`");
};
*code_field = code;
}
SubdiagnosticKind::Label
| SubdiagnosticKind::Note
| SubdiagnosticKind::Help
| SubdiagnosticKind::Warn
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
}
self.kind.set_once((kind, span));
kind_slug.set_once(((kind, slug), span))
}
Ok(())
Ok(kind_slug.map(|(kind_slug, _)| kind_slug))
}
fn generate_field_code(
&mut self,
binding: &BindingInfo<'_>,
is_suggestion: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
/// Generates the code for a field with no attributes.
fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
let ast = binding.ast();
let inner_ty = FieldInnerTy::from_type(&ast.ty);
let info = FieldInfo {
binding: binding,
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
span: &ast.span(),
};
for attr in &ast.attrs {
let name = attr.path.segments.last().unwrap().ident.to_string();
let name = name.as_str();
let span = attr.span().unwrap();
let meta = attr.parse_meta()?;
match meta {
Meta::Path(_) => match name {
"primary_span" => {
report_error_if_not_applied_to_span(attr, &info)?;
self.span_field.set_once((binding.binding.clone(), span));
return Ok(quote! {});
}
"applicability" if is_suggestion => {
report_error_if_not_applied_to_applicability(attr, &info)?;
let binding = binding.binding.clone();
self.applicability.set_once((quote! { #binding }, span));
return Ok(quote! {});
}
"applicability" => {
span_err(span, "`#[applicability]` is only valid on suggestions").emit();
return Ok(quote! {});
}
"skip_arg" => {
return Ok(quote! {});
}
_ => throw_invalid_attr!(attr, &meta, |diag| {
diag.help(
"only `primary_span`, `applicability` and `skip_arg` are valid field \
attributes",
)
}),
},
_ => throw_invalid_attr!(attr, &meta),
}
}
let ident = ast.ident.as_ref().unwrap();
assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
let diag = &self.diag;
let generated = quote! {
let ident = ast.ident.as_ref().unwrap();
quote! {
#diag.set_arg(
stringify!(#ident),
#binding
);
};
Ok(inner_ty.with(binding, generated))
}
}
fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
self.identify_kind()?;
let Some(kind) = self.kind.map(|(kind, _)| kind) else {
/// Generates the necessary code for all attributes on a field.
fn generate_field_attr_code(
&mut self,
binding: &BindingInfo<'_>,
kind: &SubdiagnosticKind,
) -> TokenStream {
let ast = binding.ast();
assert!(ast.attrs.len() > 0, "field without attributes generating attr code");
// Abstract over `Vec<T>` and `Option<T>` fields using `FieldInnerTy`, which will
// apply the generated code on each element in the `Vec` or `Option`.
let inner_ty = FieldInnerTy::from_type(&ast.ty);
ast.attrs
.iter()
.map(|attr| {
let info = FieldInfo {
binding,
ty: inner_ty.inner_type().unwrap_or(&ast.ty),
span: &ast.span(),
};
let generated = self
.generate_field_code_inner(kind, attr, info)
.unwrap_or_else(|v| v.to_compile_error());
inner_ty.with(binding, generated)
})
.collect()
}
fn generate_field_code_inner(
&mut self,
kind: &SubdiagnosticKind,
attr: &Attribute,
info: FieldInfo<'_>,
) -> Result<TokenStream, DiagnosticDeriveError> {
let meta = attr.parse_meta()?;
match meta {
Meta::Path(path) => self.generate_field_code_inner_path(kind, attr, info, path),
Meta::List(list @ MetaList { .. }) => {
self.generate_field_code_inner_list(kind, attr, info, list)
}
_ => throw_invalid_attr!(attr, &meta),
}
}
/// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`).
fn generate_field_code_inner_path(
&mut self,
kind: &SubdiagnosticKind,
attr: &Attribute,
info: FieldInfo<'_>,
path: Path,
) -> Result<TokenStream, DiagnosticDeriveError> {
let span = attr.span().unwrap();
let ident = &path.segments.last().unwrap().ident;
let name = ident.to_string();
let name = name.as_str();
match name {
"skip_arg" => Ok(quote! {}),
"primary_span" => {
if matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) {
throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
diag.help(
"multipart suggestions use one or more `#[suggestion_part]`s rather \
than one `#[primary_span]`",
)
})
}
report_error_if_not_applied_to_span(attr, &info)?;
let binding = info.binding.binding.clone();
self.span_field.set_once((binding, span));
Ok(quote! {})
}
"suggestion_part" => {
self.has_suggestion_parts = true;
match kind {
SubdiagnosticKind::MultipartSuggestion { .. } => {
span_err(
span,
"`#[suggestion_part(...)]` attribute without `code = \"...\"`",
)
.emit();
Ok(quote! {})
}
SubdiagnosticKind::Label
| SubdiagnosticKind::Note
| SubdiagnosticKind::Help
| SubdiagnosticKind::Warn
| SubdiagnosticKind::Suggestion { .. } => {
throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
diag.help(
"`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead",
)
});
}
}
}
"applicability" => {
if let SubdiagnosticKind::Suggestion { .. }
| SubdiagnosticKind::MultipartSuggestion { .. } = kind
{
report_error_if_not_applied_to_applicability(attr, &info)?;
let binding = info.binding.binding.clone();
self.applicability.set_once((quote! { #binding }, span));
} else {
span_err(span, "`#[applicability]` is only valid on suggestions").emit();
}
Ok(quote! {})
}
_ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| {
let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
"suggestion_part"
} else {
"primary_span"
};
diag.help(format!(
"only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes",
))
}),
}
}
/// Generates the code for a `[Meta::List]`-like attribute on a field (e.g.
/// `#[suggestion_part(code = "...")]`).
fn generate_field_code_inner_list(
&mut self,
kind: &SubdiagnosticKind,
attr: &Attribute,
info: FieldInfo<'_>,
list: MetaList,
) -> Result<TokenStream, DiagnosticDeriveError> {
let span = attr.span().unwrap();
let ident = &list.path.segments.last().unwrap().ident;
let name = ident.to_string();
let name = name.as_str();
match name {
"suggestion_part" => {
if !matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) {
throw_invalid_attr!(attr, &Meta::List(list), |diag| {
diag.help(
"`#[suggestion_part(...)]` is only valid in multipart suggestions",
)
})
}
self.has_suggestion_parts = true;
report_error_if_not_applied_to_span(attr, &info)?;
let mut code = None;
for nested_attr in list.nested.iter() {
let NestedMeta::Meta(ref meta) = nested_attr else {
throw_invalid_nested_attr!(attr, &nested_attr);
};
let span = meta.span().unwrap();
let nested_name = meta.path().segments.last().unwrap().ident.to_string();
let nested_name = nested_name.as_str();
let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else {
throw_invalid_nested_attr!(attr, &nested_attr);
};
match nested_name {
"code" => {
let formatted_str = self.build_format(&value.value(), value.span());
code.set_once((formatted_str, span));
}
_ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
diag.help("`code` is the only valid nested attribute")
}),
}
}
let Some((code, _)) = code else {
span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`")
.emit();
return Ok(quote! {});
};
let binding = info.binding;
Ok(quote! { suggestions.push((#binding, #code)); })
}
_ => throw_invalid_attr!(attr, &Meta::List(list), |diag| {
let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind {
"suggestion_part"
} else {
"primary_span"
};
diag.help(format!(
"only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes",
))
}),
}
}
pub fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
let Some((kind, slug)) = self.identify_kind()? else {
throw_span_err!(
self.variant.ast().ident.span().unwrap(),
"subdiagnostic kind not specified"
);
};
let is_suggestion = matches!(kind, SubdiagnosticKind::Suggestion(_));
let mut args = TokenStream::new();
for binding in self.variant.bindings() {
let arg = self
.generate_field_code(binding, is_suggestion)
.unwrap_or_else(|v| v.to_compile_error());
args.extend(arg);
}
// Missing slug errors will already have been reported.
let slug = self
.slug
.as_ref()
.map(|(slug, _)| slug.clone())
.unwrap_or_else(|| parse_quote! { you::need::to::specify::a::slug });
let code = match self.code.as_ref() {
Some((code, _)) => Some(quote! { #code }),
None if is_suggestion => {
span_err(self.span, "suggestion without `code = \"...\"`").emit();
Some(quote! { /* macro error */ "..." })
let init = match &kind {
SubdiagnosticKind::Label
| SubdiagnosticKind::Note
| SubdiagnosticKind::Help
| SubdiagnosticKind::Warn
| SubdiagnosticKind::Suggestion { .. } => quote! {},
SubdiagnosticKind::MultipartSuggestion { .. } => {
quote! { let mut suggestions = Vec::new(); }
}
None => None,
};
let attr_args: TokenStream = self
.variant
.bindings()
.iter()
.filter(|binding| !binding.ast().attrs.is_empty())
.map(|binding| self.generate_field_attr_code(binding, &kind))
.collect();
let span_field = self.span_field.as_ref().map(|(span, _)| span);
let applicability = match self.applicability.clone() {
Some((applicability, _)) => Some(applicability),
None if is_suggestion => {
span_err(self.span, "suggestion without `applicability`").emit();
Some(quote! { rustc_errors::Applicability::Unspecified })
}
None => None,
};
let applicability = self.applicability.take().map_or_else(
|| quote! { rustc_errors::Applicability::Unspecified },
|(applicability, _)| applicability,
);
let diag = &self.diag;
let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind);
let message = quote! { rustc_errors::fluent::#slug };
let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) {
if let Some(span) = span_field {
quote! { #diag.#name(#span, #message, #code, #applicability); }
} else {
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
quote! { unreachable!(); }
let call = match kind {
SubdiagnosticKind::Suggestion { suggestion_kind, code } => {
if let Some(span) = span_field {
let style = suggestion_kind.to_suggestion_style();
quote! { #diag.#name(#span, #message, #code, #applicability, #style); }
} else {
span_err(self.span, "suggestion without `#[primary_span]` field").emit();
quote! { unreachable!(); }
}
}
} else if matches!(kind, SubdiagnosticKind::Label) {
if let Some(span) = span_field {
quote! { #diag.#name(#span, #message); }
} else {
span_err(self.span, "label without `#[primary_span]` field").emit();
quote! { unreachable!(); }
SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => {
if !self.has_suggestion_parts {
span_err(
self.span,
"multipart suggestion without any `#[suggestion_part(...)]` fields",
)
.emit();
}
let style = suggestion_kind.to_suggestion_style();
quote! { #diag.#name(#message, suggestions, #applicability, #style); }
}
} else {
if let Some(span) = span_field {
quote! { #diag.#name(#span, #message); }
} else {
quote! { #diag.#name(#message); }
SubdiagnosticKind::Label => {
if let Some(span) = span_field {
quote! { #diag.#name(#span, #message); }
} else {
span_err(self.span, "label without `#[primary_span]` field").emit();
quote! { unreachable!(); }
}
}
_ => {
if let Some(span) = span_field {
quote! { #diag.#name(#span, #message); }
} else {
quote! { #diag.#name(#message); }
}
}
};
let plain_args: TokenStream = self
.variant
.bindings()
.iter()
.filter(|binding| binding.ast().attrs.is_empty())
.map(|binding| self.generate_field_set_arg(binding))
.collect();
Ok(quote! {
#init
#attr_args
#call
#args
#plain_args
})
}
}

View File

@ -171,8 +171,13 @@ decl_derive!(
suggestion_short,
suggestion_hidden,
suggestion_verbose,
multipart_suggestion,
multipart_suggestion_short,
multipart_suggestion_hidden,
multipart_suggestion_verbose,
// field attributes
skip_arg,
primary_span,
suggestion_part,
applicability)] => diagnostics::session_subdiagnostic_derive
);

View File

@ -844,6 +844,12 @@ impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> {
}
}
impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for &[T] {
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|t| t.try_fold_with(folder))

View File

@ -944,9 +944,11 @@ supported_targets! {
("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
("i686-unknown-openbsd", i686_unknown_openbsd),
("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
("powerpc64-unknown-openbsd", powerpc64_unknown_openbsd),
("riscv64gc-unknown-openbsd", riscv64gc_unknown_openbsd),
("sparc64-unknown-openbsd", sparc64_unknown_openbsd),
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
("powerpc-unknown-openbsd", powerpc_unknown_openbsd),
("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),

View File

@ -0,0 +1,17 @@
use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.cpu = "ppc64".into();
base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
base.max_atomic_width = Some(64);
Target {
llvm_target: "powerpc64-unknown-openbsd".into(),
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64".into(),
arch: "powerpc64".into(),
options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base },
}
}

View File

@ -0,0 +1,18 @@
use crate::spec::{CodeModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
llvm_target: "riscv64-unknown-openbsd".into(),
pointer_width: 64,
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic-rv64".into(),
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
..super::openbsd_base::opts()
},
}
}

View File

@ -21,7 +21,6 @@ use crate::errors::{
};
use crate::type_error_struct;
use super::suggest_call_constructor;
use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
@ -44,7 +43,7 @@ use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
use rustc_middle::ty::error::TypeError::FieldMisMatch;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable};
use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitable};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
@ -2141,15 +2140,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
field: Ident,
) -> Ty<'tcx> {
debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
let expr_t = self.check_expr(base);
let expr_t = self.structurally_resolved_type(base.span, expr_t);
let base_ty = self.check_expr(base);
let base_ty = self.structurally_resolved_type(base.span, base_ty);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
while let Some((base_t, _)) = autoderef.next() {
debug!("base_t: {:?}", base_t);
match base_t.kind() {
let mut autoderef = self.autoderef(expr.span, base_ty);
while let Some((deref_base_ty, _)) = autoderef.next() {
debug!("deref_base_ty: {:?}", deref_base_ty);
match deref_base_ty.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
debug!("struct named {:?}", base_t);
debug!("struct named {:?}", deref_base_ty);
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), self.body_id);
let fields = &base_def.non_enum_variant().fields;
@ -2197,23 +2196,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// (#90483) apply adjustments to avoid ExprUseVisitor from
// creating erroneous projection.
self.apply_adjustments(base, adjustments);
self.ban_private_field_access(expr, expr_t, field, did);
self.ban_private_field_access(expr, base_ty, field, did);
return field_ty;
}
if field.name == kw::Empty {
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
self.ban_take_value_of_method(expr, expr_t, field);
} else if !expr_t.is_primitive_ty() {
self.ban_nonexisting_field(field, base, expr, expr_t);
} else if self.method_exists(field, base_ty, expr.hir_id, true) {
self.ban_take_value_of_method(expr, base_ty, field);
} else if !base_ty.is_primitive_ty() {
self.ban_nonexisting_field(field, base, expr, base_ty);
} else {
let field_name = field.to_string();
let mut err = type_error_struct!(
self.tcx().sess,
field.span,
expr_t,
base_ty,
E0610,
"`{expr_t}` is a primitive type and therefore doesn't have fields",
"`{base_ty}` is a primitive type and therefore doesn't have fields",
);
let is_valid_suffix = |field: &str| {
if field == "f32" || field == "f64" {
@ -2251,7 +2250,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
};
if let ty::Infer(ty::IntVar(_)) = expr_t.kind()
if let ty::Infer(ty::IntVar(_)) = base_ty.kind()
&& let ExprKind::Lit(Spanned {
node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed),
..
@ -2280,35 +2279,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx().ty_error()
}
fn check_call_constructor(
&self,
err: &mut Diagnostic,
base: &'tcx hir::Expr<'tcx>,
def_id: DefId,
) {
if let Some(local_id) = def_id.as_local() {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id);
let node = self.tcx.hir().get(hir_id);
if let Some(fields) = node.tuple_fields() {
let kind = match self.tcx.opt_def_kind(local_id) {
Some(DefKind::Ctor(of, _)) => of,
_ => return,
};
suggest_call_constructor(base.span, kind, fields.len(), err);
}
} else {
// The logic here isn't smart but `associated_item_def_ids`
// doesn't work nicely on local.
if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) {
let parent_def_id = self.tcx.parent(def_id);
let fields = self.tcx.associated_item_def_ids(parent_def_id);
suggest_call_constructor(base.span, of, fields.len(), err);
}
}
}
fn suggest_await_on_field_access(
&self,
err: &mut Diagnostic,
@ -2351,40 +2321,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn ban_nonexisting_field(
&self,
field: Ident,
ident: Ident,
base: &'tcx hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
expr_t: Ty<'tcx>,
base_ty: Ty<'tcx>,
) {
debug!(
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
field, base, expr, expr_t
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
ident, base, expr, base_ty
);
let mut err = self.no_such_field_err(field, expr_t, base.hir_id);
let mut err = self.no_such_field_err(ident, base_ty, base.hir_id);
match *expr_t.peel_refs().kind() {
match *base_ty.peel_refs().kind() {
ty::Array(_, len) => {
self.maybe_suggest_array_indexing(&mut err, expr, base, field, len);
self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len);
}
ty::RawPtr(..) => {
self.suggest_first_deref_field(&mut err, expr, base, field);
self.suggest_first_deref_field(&mut err, expr, base, ident);
}
ty::Adt(def, _) if !def.is_enum() => {
self.suggest_fields_on_recordish(&mut err, def, field, expr.span);
self.suggest_fields_on_recordish(&mut err, def, ident, expr.span);
}
ty::Param(param_ty) => {
self.point_at_param_definition(&mut err, param_ty);
}
ty::Opaque(_, _) => {
self.suggest_await_on_field_access(&mut err, field, base, expr_t.peel_refs());
}
ty::FnDef(def_id, _) => {
self.check_call_constructor(&mut err, base, def_id);
self.suggest_await_on_field_access(&mut err, ident, base, base_ty.peel_refs());
}
_ => {}
}
if field.name == kw::Await {
self.suggest_fn_call(&mut err, base, base_ty, |output_ty| {
if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() {
def.non_enum_variant().fields.iter().any(|field| {
field.ident(self.tcx) == ident
&& field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx)
})
} else if let ty::Tuple(tys) = output_ty.kind()
&& let Ok(idx) = ident.as_str().parse::<usize>()
{
idx < tys.len()
} else {
false
}
});
if ident.name == kw::Await {
// We know by construction that `<expr>.await` is either on Rust 2015
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
err.note("to `.await` a `Future`, switch to Rust 2018 or later");

View File

@ -2,6 +2,7 @@ use super::FnCtxt;
use crate::astconv::AstConv;
use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
use hir::def_id::DefId;
use rustc_ast::util::parser::ExprPrecedence;
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir;
@ -61,70 +62,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pointing_at_return_type
}
/// When encountering an fn-like ctor that needs to unify with a value, check whether calling
/// the ctor would successfully solve the type mismatch and if so, suggest it:
/// When encountering an fn-like type, try accessing the output of the type
/// // and suggesting calling it if it satisfies a predicate (i.e. if the
/// output has a method or a field):
/// ```compile_fail,E0308
/// fn foo(x: usize) -> usize { x }
/// let x: usize = foo; // suggest calling the `foo` function: `foo(42)`
/// ```
fn suggest_fn_call(
pub(crate) fn suggest_fn_call(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>) -> bool,
) -> bool {
let (def_id, output, inputs) = match *found.kind() {
ty::FnDef(def_id, _) => {
let fn_sig = found.fn_sig(self.tcx);
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len())
}
ty::Closure(def_id, substs) => {
let fn_sig = substs.as_closure().sig();
(def_id, fn_sig.output(), fn_sig.inputs().skip_binder().len() - 1)
}
ty::Opaque(def_id, substs) => {
let sig = self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
pred.kind().rebind(proj.term.ty().unwrap()),
args.len(),
))
} else {
None
}
});
if let Some((output, inputs)) = sig {
(def_id, output, inputs)
} else {
return false;
}
}
_ => return false,
};
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
let output = self.normalize_associated_types_in(expr.span, output);
if !output.is_ty_var() && self.can_coerce(output, expected) {
let (sugg_call, mut applicability) = match inputs {
let Some((def_id_or_name, output, inputs)) = self.extract_callable_info(expr, found)
else { return false; };
if can_satisfy(output) {
let (sugg_call, mut applicability) = match inputs.len() {
0 => ("".to_string(), Applicability::MachineApplicable),
1..=4 => (
(0..inputs).map(|_| "_").collect::<Vec<_>>().join(", "),
Applicability::MachineApplicable,
inputs
.iter()
.map(|ty| {
if ty.is_suggestable(self.tcx, false) {
format!("/* {ty} */")
} else {
"".to_string()
}
})
.collect::<Vec<_>>()
.join(", "),
Applicability::HasPlaceholders,
),
_ => ("...".to_string(), Applicability::HasPlaceholders),
_ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
};
let msg = match self.tcx.def_kind(def_id) {
DefKind::Fn => "call this function",
DefKind::Closure | DefKind::OpaqueTy => "call this closure",
DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct",
DefKind::Ctor(CtorOf::Variant, _) => "instantiate this tuple variant",
_ => "call this function",
let msg = match def_id_or_name {
DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
DefKind::Ctor(CtorOf::Struct, _) => "instantiate this tuple struct".to_string(),
DefKind::Ctor(CtorOf::Variant, _) => {
"instantiate this tuple variant".to_string()
}
kind => format!("call this {}", kind.descr(def_id)),
},
DefIdOrName::Name(name) => format!("call this {name}"),
};
let sugg = match expr.kind {
@ -161,6 +143,179 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}
fn extract_callable_info(
&self,
expr: &Expr<'_>,
found: Ty<'tcx>,
) -> Option<(DefIdOrName, Ty<'tcx>, Vec<Ty<'tcx>>)> {
// Autoderef is useful here because sometimes we box callables, etc.
let Some((def_id_or_name, output, inputs)) = self.autoderef(expr.span, found).silence_errors().find_map(|(found, _)| {
match *found.kind() {
ty::FnPtr(fn_sig) =>
Some((DefIdOrName::Name("function pointer"), fn_sig.output(), fn_sig.inputs())),
ty::FnDef(def_id, _) => {
let fn_sig = found.fn_sig(self.tcx);
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs()))
}
ty::Closure(def_id, substs) => {
let fn_sig = substs.as_closure().sig();
Some((DefIdOrName::DefId(def_id), fn_sig.output(), fn_sig.inputs().map_bound(|inputs| &inputs[1..])))
}
ty::Opaque(def_id, substs) => {
self.tcx.bound_item_bounds(def_id).subst(self.tcx, substs).iter().find_map(|pred| {
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
DefIdOrName::DefId(def_id),
pred.kind().rebind(proj.term.ty().unwrap()),
pred.kind().rebind(args.as_slice()),
))
} else {
None
}
})
}
ty::Dynamic(data, _) => {
data.iter().find_map(|pred| {
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
// for existential projection, substs are shifted over by 1
&& let ty::Tuple(args) = proj.substs.type_at(0).kind()
{
Some((
DefIdOrName::Name("trait object"),
pred.rebind(proj.term.ty().unwrap()),
pred.rebind(args.as_slice()),
))
} else {
None
}
})
}
ty::Param(param) => {
let def_id = self.tcx.generics_of(self.body_id.owner).type_param(&param, self.tcx).def_id;
self.tcx.predicates_of(self.body_id.owner).predicates.iter().find_map(|(pred, _)| {
if let ty::PredicateKind::Projection(proj) = pred.kind().skip_binder()
&& Some(proj.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output()
&& proj.projection_ty.self_ty() == found
// args tuple will always be substs[1]
&& let ty::Tuple(args) = proj.projection_ty.substs.type_at(1).kind()
{
Some((
DefIdOrName::DefId(def_id),
pred.kind().rebind(proj.term.ty().unwrap()),
pred.kind().rebind(args.as_slice()),
))
} else {
None
}
})
}
_ => None,
}
}) else { return None; };
let output = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, output);
let inputs = inputs
.skip_binder()
.iter()
.map(|ty| {
self.replace_bound_vars_with_fresh_vars(
expr.span,
infer::FnCall,
inputs.rebind(*ty),
)
})
.collect();
// We don't want to register any extra obligations, which should be
// implied by wf, but also because that would possibly result in
// erroneous errors later on.
let infer::InferOk { value: output, obligations: _ } =
self.normalize_associated_types_in_as_infer_ok(expr.span, output);
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
}
pub fn suggest_two_fn_call(
&self,
err: &mut Diagnostic,
lhs_expr: &'tcx hir::Expr<'tcx>,
lhs_ty: Ty<'tcx>,
rhs_expr: &'tcx hir::Expr<'tcx>,
rhs_ty: Ty<'tcx>,
can_satisfy: impl FnOnce(Ty<'tcx>, Ty<'tcx>) -> bool,
) -> bool {
let Some((_, lhs_output_ty, lhs_inputs)) = self.extract_callable_info(lhs_expr, lhs_ty)
else { return false; };
let Some((_, rhs_output_ty, rhs_inputs)) = self.extract_callable_info(rhs_expr, rhs_ty)
else { return false; };
if can_satisfy(lhs_output_ty, rhs_output_ty) {
let mut sugg = vec![];
let mut applicability = Applicability::MachineApplicable;
for (expr, inputs) in [(lhs_expr, lhs_inputs), (rhs_expr, rhs_inputs)] {
let (sugg_call, this_applicability) = match inputs.len() {
0 => ("".to_string(), Applicability::MachineApplicable),
1..=4 => (
inputs
.iter()
.map(|ty| {
if ty.is_suggestable(self.tcx, false) {
format!("/* {ty} */")
} else {
"/* value */".to_string()
}
})
.collect::<Vec<_>>()
.join(", "),
Applicability::HasPlaceholders,
),
_ => ("/* ... */".to_string(), Applicability::HasPlaceholders),
};
applicability = applicability.max(this_applicability);
match expr.kind {
hir::ExprKind::Call(..)
| hir::ExprKind::Path(..)
| hir::ExprKind::Index(..)
| hir::ExprKind::Lit(..) => {
sugg.extend([(expr.span.shrink_to_hi(), format!("({sugg_call})"))]);
}
hir::ExprKind::Closure { .. } => {
// Might be `{ expr } || { bool }`
applicability = Applicability::MaybeIncorrect;
sugg.extend([
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
]);
}
_ => {
sugg.extend([
(expr.span.shrink_to_lo(), "(".to_string()),
(expr.span.shrink_to_hi(), format!(")({sugg_call})")),
]);
}
}
}
err.multipart_suggestion_verbose(
format!("use parentheses to call these"),
sugg,
applicability,
);
true
} else {
false
}
}
pub fn suggest_deref_ref_or_into(
&self,
err: &mut Diagnostic,
@ -178,12 +333,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(sp, &msg, suggestion, applicability);
}
} else if let (ty::FnDef(def_id, ..), true) =
(&found.kind(), self.suggest_fn_call(err, expr, expected, found))
} else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
&& let ty::FnDef(def_id, ..) = &found.kind()
&& let Some(sp) = self.tcx.hir().span_if_local(*def_id)
{
if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
err.span_label(sp, format!("{found} defined here"));
}
err.span_label(sp, format!("{found} defined here"));
} else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
if !methods.is_empty() {
@ -911,3 +1065,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
enum DefIdOrName {
DefId(DefId),
Name(&'static str),
}

View File

@ -31,7 +31,7 @@ use std::cmp::Ordering;
use std::iter;
use super::probe::{Mode, ProbeScope};
use super::{super::suggest_call_constructor, CandidateSource, MethodError, NoMatchData};
use super::{CandidateSource, MethodError, NoMatchData};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@ -363,44 +363,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
if self.is_fn_ty(rcvr_ty, span) {
if let SelfSource::MethodCall(expr) = source {
let suggest = if let ty::FnDef(def_id, _) = rcvr_ty.kind() {
if let Some(local_id) = def_id.as_local() {
let hir_id = tcx.hir().local_def_id_to_hir_id(local_id);
let node = tcx.hir().get(hir_id);
let fields = node.tuple_fields();
if let Some(fields) = fields
&& let Some(DefKind::Ctor(of, _)) = self.tcx.opt_def_kind(local_id) {
Some((fields.len(), of))
} else {
None
}
} else {
// The logic here isn't smart but `associated_item_def_ids`
// doesn't work nicely on local.
if let DefKind::Ctor(of, _) = tcx.def_kind(def_id) {
let parent_def_id = tcx.parent(*def_id);
Some((tcx.associated_item_def_ids(parent_def_id).len(), of))
} else {
None
}
}
} else {
None
};
// If the function is a tuple constructor, we recommend that they call it
if let Some((fields, kind)) = suggest {
suggest_call_constructor(expr.span, kind, fields, &mut err);
} else {
// General case
err.span_label(
expr.span,
"this is a function, perhaps you wish to call it",
);
}
}
if let SelfSource::MethodCall(rcvr_expr) = source {
self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
let call_expr = self
.tcx
.hir()
.expect_expr(self.tcx.hir().get_parent_node(rcvr_expr.hir_id));
let probe = self.lookup_probe(
span,
item_name,
output_ty,
call_expr,
ProbeScope::AllTraits,
);
probe.is_ok()
});
}
let mut custom_span_label = false;

View File

@ -96,7 +96,6 @@ use check::{check_abi, check_fn, check_mod_item_types};
pub use diverges::Diverges;
pub use expectation::Expectation;
pub use fn_ctxt::*;
use hir::def::CtorOf;
pub use inherited::{Inherited, InheritedBuilder};
use crate::astconv::AstConv;
@ -960,31 +959,3 @@ fn has_expected_num_generic_args<'tcx>(
generics.count() == expected + if generics.has_self { 1 } else { 0 }
})
}
/// Suggests calling the constructor of a tuple struct or enum variant
///
/// * `snippet` - The snippet of code that references the constructor
/// * `span` - The span of the snippet
/// * `params` - The number of parameters the constructor accepts
/// * `err` - A mutable diagnostic builder to add the suggestion to
fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
// Note: tuple-structs don't have named fields, so just use placeholders
let args = vec!["_"; params].join(", ");
let applicable = if params > 0 {
Applicability::HasPlaceholders
} else {
// When n = 0, it's an empty-tuple struct/enum variant
// so we trivially know how to construct it
Applicability::MachineApplicable
};
let kind = match kind {
CtorOf::Struct => "a struct",
CtorOf::Variant => "an enum variant",
};
err.span_label(span, &format!("this is the constructor of {kind}"));
err.multipart_suggestion(
"call the constructor",
vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), format!(")({args})"))],
applicable,
);
}

View File

@ -410,26 +410,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}");
if !lhs_expr.span.eq(&rhs_expr.span) {
self.add_type_neq_err_label(
&mut err,
lhs_expr.span,
lhs_ty,
rhs_ty,
rhs_expr,
op,
is_assign,
expected,
);
self.add_type_neq_err_label(
&mut err,
rhs_expr.span,
rhs_ty,
lhs_ty,
lhs_expr,
op,
is_assign,
expected,
);
err.span_label(lhs_expr.span, lhs_ty.to_string());
err.span_label(rhs_expr.span, rhs_ty.to_string());
}
self.note_unmet_impls_on_type(&mut err, errors);
(err, missing_trait, use_output)
@ -468,17 +450,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
let is_compatible = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
Some(rhs_ty),
Some(rhs_expr),
Op::Binary(op, is_assign),
expected,
)
.is_ok()
};
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
// `a += b` => `*a += b` if a is a mut ref.
if is_assign == IsAssign::Yes
&& let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
suggest_deref_binop(lhs_deref_ty);
if !op.span.can_be_used_for_suggestions() {
// Suppress suggestions when lhs and rhs are not in the same span as the error
} else if is_assign == IsAssign::Yes
&& let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty)
{
suggest_deref_binop(lhs_deref_ty);
} else if is_assign == IsAssign::No
&& let Ref(_, lhs_deref_ty, _) = lhs_ty.kind() {
if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty, lhs_expr.span) {
&& let Ref(_, lhs_deref_ty, _) = lhs_ty.kind()
{
if self.type_is_copy_modulo_regions(
self.param_env,
*lhs_deref_ty,
lhs_expr.span,
) {
suggest_deref_binop(*lhs_deref_ty);
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
is_compatible(lhs_ty, rhs_ty)
}) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
is_compatible(lhs_ty, rhs_ty)
}) || self.suggest_two_fn_call(
&mut err,
rhs_expr,
rhs_ty,
lhs_expr,
lhs_ty,
|lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty),
) {
// Cool
}
if let Some(missing_trait) = missing_trait {
let mut visitor = TypeParamVisitor(vec![]);
visitor.visit_ty(lhs_ty);
@ -548,69 +563,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(lhs_ty, rhs_ty, return_ty)
}
/// If one of the types is an uncalled function and calling it would yield the other type,
/// suggest calling the function. Returns `true` if suggestion would apply (even if not given).
fn add_type_neq_err_label(
&self,
err: &mut Diagnostic,
span: Span,
ty: Ty<'tcx>,
other_ty: Ty<'tcx>,
other_expr: &'tcx hir::Expr<'tcx>,
op: hir::BinOp,
is_assign: IsAssign,
expected: Expectation<'tcx>,
) -> bool /* did we suggest to call a function because of missing parentheses? */ {
err.span_label(span, ty.to_string());
if let FnDef(def_id, _) = *ty.kind() {
if !self.tcx.has_typeck_results(def_id) {
return false;
}
// FIXME: Instead of exiting early when encountering bound vars in
// the function signature, consider keeping the binder here and
// propagating it downwards.
let Some(fn_sig) = self.tcx.fn_sig(def_id).no_bound_vars() else {
return false;
};
let other_ty = if let FnDef(def_id, _) = *other_ty.kind() {
if !self.tcx.has_typeck_results(def_id) {
return false;
}
// We're emitting a suggestion, so we can just ignore regions
self.tcx.fn_sig(def_id).skip_binder().output()
} else {
other_ty
};
if self
.lookup_op_method(
fn_sig.output(),
Some(other_ty),
Some(other_expr),
Op::Binary(op, is_assign),
expected,
)
.is_ok()
{
let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
("( /* arguments */ )", Applicability::HasPlaceholders)
} else {
("()", Applicability::MaybeIncorrect)
};
err.span_suggestion_verbose(
span.shrink_to_hi(),
"you might have forgotten to call this function",
variable_snippet,
applicability,
);
return true;
}
}
false
}
/// Provide actionable suggestions when trying to add two strings with incorrect types,
/// like `&str + &str`, `String + String` and `&str + &String`.
///

View File

@ -1262,7 +1262,11 @@ fn check_impl<'tcx>(
}
None => {
let self_ty = tcx.type_of(item.def_id);
let self_ty = wfcx.normalize(item.span, None, self_ty);
let self_ty = wfcx.normalize(
item.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
self_ty,
);
wfcx.register_wf_obligation(
ast_self_ty.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner())),
@ -1307,7 +1311,11 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
if !ty.needs_subst() {
wfcx.register_wf_obligation(tcx.def_span(param.def_id), None, ty.into());
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
Some(WellFormedLoc::Ty(param.def_id.expect_local())),
ty.into(),
);
}
}
}
@ -1512,7 +1520,14 @@ fn check_fn_or_method<'tcx>(
);
}
wfcx.register_wf_obligation(hir_decl.output.span(), None, sig.output().into());
wfcx.register_wf_obligation(
hir_decl.output.span(),
Some(WellFormedLoc::Param {
function: def_id,
param_idx: sig.inputs().len().try_into().unwrap(),
}),
sig.output().into(),
);
check_where_clauses(wfcx, span, def_id);
}

View File

@ -140,6 +140,10 @@ fn diagnostic_hir_wf_check<'tcx>(
hir::Node::ForeignItem(ForeignItem {
kind: ForeignItemKind::Static(ty, _), ..
}) => Some(*ty),
hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Type { default: Some(ty), .. },
..
}) => Some(*ty),
ref node => bug!("Unexpected node {:?}", node),
},
WellFormedLoc::Param { function: _, param_idx } => {

View File

@ -137,11 +137,9 @@ mod imp {
}
}
#[cfg(target_os = "macos")]
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
mod imp {
use crate::fs::File;
use crate::io::Read;
use crate::sys::os::errno;
use crate::io;
use crate::sys::weak::weak;
use libc::{c_int, c_void, size_t};
@ -155,7 +153,7 @@ mod imp {
for s in v.chunks_mut(256) {
let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
if ret == -1 {
panic!("unexpected getentropy error: {}", errno());
panic!("unexpected getentropy error: {}", io::Error::last_os_error());
}
}
true
@ -163,14 +161,64 @@ mod imp {
.unwrap_or(false)
}
#[cfg(target_os = "macos")]
fn fallback_fill_bytes(v: &mut [u8]) {
use crate::fs::File;
use crate::io::Read;
let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
file.read_exact(v).expect("failed to read /dev/urandom")
}
// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
//
// This is very heavyweight compared to the alternatives, but they may not be usable:
// - `getentropy` was added in iOS 10, but we support a minimum of iOS 7
// - `/dev/urandom` is not accessible inside the iOS app sandbox.
//
// Therefore `SecRandomCopyBytes` is only used on older iOS versions where no
// better options are present.
#[cfg(target_os = "ios")]
fn fallback_fill_bytes(v: &mut [u8]) {
use crate::ptr;
enum SecRandom {}
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = ptr::null();
extern "C" {
fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
}
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
if ret == -1 {
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
}
}
// All supported versions of watchOS (>= 5) have support for `getentropy`.
#[cfg(target_os = "watchos")]
#[cold]
fn fallback_fill_bytes(_: &mut [u8]) {
unreachable!()
}
pub fn fill_bytes(v: &mut [u8]) {
if getentropy_fill_bytes(v) {
return;
}
// for older macos which doesn't support getentropy
let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
file.read_exact(v).expect("failed to read /dev/urandom")
// Older macOS versions (< 10.12) don't support `getentropy`. Fallback to
// reading from `/dev/urandom` on these systems.
//
// Older iOS versions (< 10) don't support it either. Fallback to
// `SecRandomCopyBytes` on these systems. On watchOS, this is unreachable
// because the minimum supported version is 5 while `getentropy` became accessible
// in 3.
fallback_fill_bytes(v)
}
}
@ -189,36 +237,6 @@ mod imp {
}
}
// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(any(target_os = "ios", target_os = "watchos"))]
mod imp {
use crate::io;
use crate::ptr;
use libc::{c_int, size_t};
enum SecRandom {}
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = ptr::null();
extern "C" {
fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
}
pub fn fill_bytes(v: &mut [u8]) {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
if ret == -1 {
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
}
}
}
#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
mod imp {
use crate::ptr;

View File

@ -228,8 +228,6 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
pub const MSG_PEEK: c_int = 0x2;
pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 0x800;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct linger {
@ -503,6 +501,8 @@ pub struct FILE_END_OF_FILE_INFO {
pub EndOfFile: LARGE_INTEGER,
}
/// NB: Use carefully! In general using this as a reference is likely to get the
/// provenance wrong for the `rest` field!
#[repr(C)]
pub struct REPARSE_DATA_BUFFER {
pub ReparseTag: c_uint,
@ -511,6 +511,8 @@ pub struct REPARSE_DATA_BUFFER {
pub rest: (),
}
/// NB: Use carefully! In general using this as a reference is likely to get the
/// provenance wrong for the `PathBuffer` field!
#[repr(C)]
pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
pub SubstituteNameOffset: c_ushort,
@ -521,6 +523,8 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
pub PathBuffer: WCHAR,
}
/// NB: Use carefully! In general using this as a reference is likely to get the
/// provenance wrong for the `PathBuffer` field!
#[repr(C)]
pub struct MOUNT_POINT_REPARSE_BUFFER {
pub SubstituteNameOffset: c_ushort,
@ -1032,7 +1036,6 @@ extern "system" {
pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
pub fn LoadLibraryExA(lplibfilename: *const i8, hfile: HANDLE, dwflags: u32) -> HINSTANCE;
pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);

View File

@ -21,9 +21,52 @@
use crate::ffi::{c_void, CStr};
use crate::ptr::NonNull;
use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sync::atomic::Ordering;
use crate::sys::c;
// This uses a static initializer to preload some imported functions.
// The CRT (C runtime) executes static initializers before `main`
// is called (for binaries) and before `DllMain` is called (for DLLs).
//
// It works by contributing a global symbol to the `.CRT$XCT` section.
// The linker builds a table of all static initializer functions.
// The CRT startup code then iterates that table, calling each
// initializer function.
//
// NOTE: User code should instead use .CRT$XCU to reliably run after std's initializer.
// If you're reading this and would like a guarantee here, please
// file an issue for discussion; currently we don't guarantee any functionality
// before main.
// See https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-170
#[used]
#[link_section = ".CRT$XCT"]
static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
/// Preload some imported functions.
///
/// Note that any functions included here will be unconditionally loaded in
/// the final binary, regardless of whether or not they're actually used.
///
/// Therefore, this should be limited to `compat_fn_optional` functions which
/// must be preloaded or any functions where lazier loading demonstrates a
/// negative performance impact in practical situations.
///
/// Currently we only preload `WaitOnAddress` and `WakeByAddressSingle`.
unsafe extern "C" fn init() {
// In an exe this code is executed before main() so is single threaded.
// In a DLL the system's loader lock will be held thereby synchronizing
// access. So the same best practices apply here as they do to running in DllMain:
// https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
//
// DO NOT do anything interesting or complicated in this function! DO NOT call
// any Rust functions or CRT functions if those functions touch any global state,
// because this function runs during global initialization. For example, DO NOT
// do any dynamic allocation, don't call LoadLibrary, etc.
// Attempt to preload the synch functions.
load_synch_functions();
}
/// Helper macro for creating CStrs from literals and symbol names.
macro_rules! ansi_str {
(sym $ident:ident) => {{
@ -75,20 +118,6 @@ impl Module {
NonNull::new(module).map(Self)
}
/// Load the library (if not already loaded)
///
/// # Safety
///
/// The module must not be unloaded.
pub unsafe fn load_system_library(name: &CStr) -> Option<Self> {
let module = c::LoadLibraryExA(
name.as_ptr(),
crate::ptr::null_mut(),
c::LOAD_LIBRARY_SEARCH_SYSTEM32,
);
NonNull::new(module).map(Self)
}
// Try to get the address of a function.
pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> {
// SAFETY:
@ -182,14 +211,10 @@ macro_rules! compat_fn_optional {
#[inline(always)]
pub fn option() -> Option<F> {
let f = PTR.load(Ordering::Acquire);
if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
}
#[cold]
fn try_load() -> Option<F> {
$load_functions;
NonNull::new(PTR.load(Ordering::Acquire)).map(|f| unsafe { mem::transmute(f) })
// Miri does not understand the way we do preloading
// therefore load the function here instead.
#[cfg(miri)] $load_functions;
NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| unsafe { mem::transmute(f) })
}
}
)+
@ -205,17 +230,14 @@ pub(super) fn load_synch_functions() {
// Try loading the library and all the required functions.
// If any step fails, then they all fail.
let library = unsafe { Module::load_system_library(MODULE_NAME) }?;
let library = unsafe { Module::new(MODULE_NAME) }?;
let wait_on_address = library.proc_address(WAIT_ON_ADDRESS)?;
let wake_by_address_single = library.proc_address(WAKE_BY_ADDRESS_SINGLE)?;
c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Release);
c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Release);
c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Relaxed);
c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Relaxed);
Some(())
}
// Try to load the module but skip loading if a previous attempt failed.
static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
let module_loaded = LOAD_MODULE.load(Ordering::Acquire) && try_load().is_some();
LOAD_MODULE.store(module_loaded, Ordering::Release)
try_load();
}

View File

@ -11,7 +11,7 @@ use crate::slice;
use crate::sync::Arc;
use crate::sys::handle::Handle;
use crate::sys::time::SystemTime;
use crate::sys::{c, cvt};
use crate::sys::{c, cvt, Align8};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::thread;
@ -326,9 +326,9 @@ impl File {
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
let mut reparse_tag = 0;
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
let mut b = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
if let Ok((_, buf)) = self.reparse_point(&mut b) {
reparse_tag = buf.ReparseTag;
reparse_tag = (*buf).ReparseTag;
}
}
Ok(FileAttr {
@ -389,9 +389,9 @@ impl File {
attr.file_size = info.AllocationSize as u64;
attr.number_of_links = Some(info.NumberOfLinks);
if attr.file_type().is_reparse_point() {
let mut b = [0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
let mut b = Align8([0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
if let Ok((_, buf)) = self.reparse_point(&mut b) {
attr.reparse_tag = buf.ReparseTag;
attr.reparse_tag = (*buf).ReparseTag;
}
}
Ok(attr)
@ -458,38 +458,46 @@ impl File {
Ok(Self { handle: self.handle.try_clone()? })
}
fn reparse_point<'a>(
// NB: returned pointer is derived from `space`, and has provenance to
// match. A raw pointer is returned rather than a reference in order to
// avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`.
fn reparse_point(
&self,
space: &'a mut [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE],
) -> io::Result<(c::DWORD, &'a c::REPARSE_DATA_BUFFER)> {
space: &mut Align8<[u8]>,
) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
unsafe {
let mut bytes = 0;
cvt({
// Grab this in advance to avoid it invalidating the pointer
// we get from `space.0.as_mut_ptr()`.
let len = space.0.len();
c::DeviceIoControl(
self.handle.as_raw_handle(),
c::FSCTL_GET_REPARSE_POINT,
ptr::null_mut(),
0,
space.as_mut_ptr() as *mut _,
space.len() as c::DWORD,
space.0.as_mut_ptr().cast(),
len as c::DWORD,
&mut bytes,
ptr::null_mut(),
)
})?;
Ok((bytes, &*(space.as_ptr() as *const c::REPARSE_DATA_BUFFER)))
const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
Ok((bytes, space.0.as_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
}
}
fn readlink(&self) -> io::Result<PathBuf> {
let mut space = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
let mut space = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let (_bytes, buf) = self.reparse_point(&mut space)?;
unsafe {
let (path_buffer, subst_off, subst_len, relative) = match buf.ReparseTag {
let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
c::IO_REPARSE_TAG_SYMLINK => {
let info: *const c::SYMBOLIC_LINK_REPARSE_BUFFER =
&buf.rest as *const _ as *const _;
ptr::addr_of!((*buf).rest).cast();
assert!(info.is_aligned());
(
&(*info).PathBuffer as *const _ as *const u16,
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
(*info).SubstituteNameOffset / 2,
(*info).SubstituteNameLength / 2,
(*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0,
@ -497,9 +505,10 @@ impl File {
}
c::IO_REPARSE_TAG_MOUNT_POINT => {
let info: *const c::MOUNT_POINT_REPARSE_BUFFER =
&buf.rest as *const _ as *const _;
ptr::addr_of!((*buf).rest).cast();
assert!(info.is_aligned());
(
&(*info).PathBuffer as *const _ as *const u16,
ptr::addr_of!((*info).PathBuffer).cast::<u16>(),
(*info).SubstituteNameOffset / 2,
(*info).SubstituteNameLength / 2,
false,
@ -649,18 +658,18 @@ impl File {
/// A buffer for holding directory entries.
struct DirBuff {
buffer: Vec<u8>,
buffer: Box<Align8<[u8; Self::BUFFER_SIZE]>>,
}
impl DirBuff {
const BUFFER_SIZE: usize = 1024;
fn new() -> Self {
const BUFFER_SIZE: usize = 1024;
Self { buffer: vec![0_u8; BUFFER_SIZE] }
Self { buffer: Box::new(Align8([0u8; Self::BUFFER_SIZE])) }
}
fn capacity(&self) -> usize {
self.buffer.len()
self.buffer.0.len()
}
fn as_mut_ptr(&mut self) -> *mut u8 {
self.buffer.as_mut_ptr().cast()
self.buffer.0.as_mut_ptr().cast()
}
/// Returns a `DirBuffIter`.
fn iter(&self) -> DirBuffIter<'_> {
@ -669,7 +678,7 @@ impl DirBuff {
}
impl AsRef<[u8]> for DirBuff {
fn as_ref(&self) -> &[u8] {
&self.buffer
&self.buffer.0
}
}
@ -697,9 +706,12 @@ impl<'a> Iterator for DirBuffIter<'a> {
// used to get the file name slice.
let (name, is_directory, next_entry) = unsafe {
let info = buffer.as_ptr().cast::<c::FILE_ID_BOTH_DIR_INFO>();
// Guaranteed to be aligned in documentation for
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info
assert!(info.is_aligned());
let next_entry = (*info).NextEntryOffset as usize;
let name = crate::slice::from_raw_parts(
(*info).FileName.as_ptr().cast::<u16>(),
ptr::addr_of!((*info).FileName).cast::<u16>(),
(*info).FileNameLength as usize / size_of::<u16>(),
);
let is_directory = ((*info).FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) != 0;
@ -1337,9 +1349,10 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let h = f.as_inner().as_raw_handle();
unsafe {
let mut data = [0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
let db = data.as_mut_ptr() as *mut c::REPARSE_MOUNTPOINT_DATA_BUFFER;
let buf = &mut (*db).ReparseTarget as *mut c::WCHAR;
let mut data = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let data_ptr = data.0.as_mut_ptr();
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
let mut i = 0;
// FIXME: this conversion is very hacky
let v = br"\??\";
@ -1359,7 +1372,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
cvt(c::DeviceIoControl(
h as *mut _,
c::FSCTL_SET_REPARSE_POINT,
data.as_ptr() as *mut _,
data_ptr.cast(),
(*db).ReparseDataLength + 8,
ptr::null_mut(),
0,

View File

@ -329,3 +329,11 @@ pub fn abort_internal() -> ! {
}
crate::intrinsics::abort();
}
/// Align the inner value to 8 bytes.
///
/// This is enough for almost all of the buffers we're likely to work with in
/// the Windows APIs we use.
#[repr(C, align(8))]
#[derive(Copy, Clone)]
pub(crate) struct Align8<T: ?Sized>(pub T);

View File

@ -432,12 +432,13 @@ impl Step for Llvm {
cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
}
if target.starts_with("riscv") && !target.contains("freebsd") {
if target.starts_with("riscv") && !target.contains("freebsd") && !target.contains("openbsd")
{
// RISC-V GCC erroneously requires linking against
// `libatomic` when using 1-byte and 2-byte C++
// atomics but the LLVM build system check cannot
// detect this. Therefore it is set manually here.
// FreeBSD uses Clang as its system compiler and
// Some BSD uses Clang as its system compiler and
// provides no libatomic in its base system so does
// not want this.
ldflags.exe.push(" -latomic");

View File

@ -277,6 +277,7 @@ target | std | host | notes
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
[`powerpc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/powerpc64
`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches)
`riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA)
@ -284,6 +285,7 @@ target | std | host | notes
`riscv32imc-esp-espidf` | ✓ | | RISC-V ESP-IDF
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64

View File

@ -12,6 +12,8 @@ The target names follow this format: `$ARCH-unknown-openbsd`, where `$ARCH` spec
|--------------------------------|-------------|------------------|
| `aarch64-unknown-openbsd` | libc++ | [64-bit ARM systems](https://www.openbsd.org/arm64.html) |
| `i686-unknown-openbsd` | libc++ | [Standard PC and clones based on the Intel i386 architecture and compatible processors](https://www.openbsd.org/i386.html) |
| `powerpc64-unknown-openbsd` | libc++ | [IBM POWER-based PowerNV systems](https://www.openbsd.org/powerpc64.html) |
| `riscv64gc-unknown-openbsd` | libc++ | [64-bit RISC-V systems](https://www.openbsd.org/riscv64.html) |
| `sparc64-unknown-openbsd` | estdc++ | [Sun UltraSPARC and Fujitsu SPARC64 systems](https://www.openbsd.org/sparc64.html) |
| `x86_64-unknown-openbsd` | libc++ | [AMD64-based systems](https://www.openbsd.org/amd64.html) |

View File

@ -167,8 +167,8 @@ enum P {
#[derive(SessionSubdiagnostic)]
enum Q {
#[bar]
//~^ ERROR `#[bar]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
//~^ ERROR `#[bar]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
@ -179,8 +179,8 @@ enum Q {
#[derive(SessionSubdiagnostic)]
enum R {
#[bar = "..."]
//~^ ERROR `#[bar = ...]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
//~^ ERROR `#[bar = ...]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
@ -191,8 +191,8 @@ enum R {
#[derive(SessionSubdiagnostic)]
enum S {
#[bar = 4]
//~^ ERROR `#[bar = ...]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
//~^ ERROR `#[bar = ...]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
@ -203,8 +203,8 @@ enum S {
#[derive(SessionSubdiagnostic)]
enum T {
#[bar("...")]
//~^ ERROR `#[bar("...")]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
//~^ ERROR `#[bar(...)]` is not a valid attribute
//~^^ ERROR cannot find attribute `bar` in this scope
A {
#[primary_span]
span: Span,
@ -215,7 +215,7 @@ enum T {
#[derive(SessionSubdiagnostic)]
enum U {
#[label(code = "...")]
//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute
A {
#[primary_span]
span: Span,
@ -232,7 +232,7 @@ enum V {
var: String,
},
B {
//~^ ERROR subdiagnostic kind not specified
//~^ ERROR subdiagnostic kind not specified
#[primary_span]
span: Span,
var: String,
@ -310,10 +310,8 @@ union AC {
#[derive(SessionSubdiagnostic)]
#[label(parser::add_paren)]
//~^ NOTE previously specified here
//~^^ NOTE previously specified here
#[label(parser::add_paren)]
//~^ ERROR specified multiple times
//~^^ ERROR specified multiple times
struct AD {
#[primary_span]
span: Span,
@ -331,16 +329,16 @@ struct AE {
#[label(parser::add_paren)]
struct AF {
#[primary_span]
//~^ NOTE previously specified here
//~^ NOTE previously specified here
span_a: Span,
#[primary_span]
//~^ ERROR specified multiple times
//~^ ERROR specified multiple times
span_b: Span,
}
#[derive(SessionSubdiagnostic)]
struct AG {
//~^ ERROR subdiagnostic kind not specified
//~^ ERROR subdiagnostic kind not specified
#[primary_span]
span: Span,
}
@ -392,27 +390,25 @@ struct AK {
#[primary_span]
span: Span,
#[applicability]
//~^ NOTE previously specified here
//~^ NOTE previously specified here
applicability_a: Applicability,
#[applicability]
//~^ ERROR specified multiple times
//~^ ERROR specified multiple times
applicability_b: Applicability,
}
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
//~^ ERROR suggestion without `applicability`
struct AL {
#[primary_span]
span: Span,
#[applicability]
//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability`
applicability: Span,
}
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
//~^ ERROR suggestion without `applicability`
struct AM {
#[primary_span]
span: Span,
@ -448,8 +444,7 @@ struct AQ;
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
//~^ ERROR suggestion without `applicability`
//~^^ ERROR suggestion without `#[primary_span]` field
//~^ ERROR suggestion without `#[primary_span]` field
struct AR {
var: String,
}
@ -519,3 +514,120 @@ struct AZ {
#[primary_span]
span: Span,
}
#[derive(SessionSubdiagnostic)]
#[suggestion(parser::add_paren, code = "...")]
//~^ ERROR suggestion without `#[primary_span]` field
struct BA {
#[suggestion_part]
//~^ ERROR `#[suggestion_part]` is not a valid attribute
span: Span,
#[suggestion_part(code = "...")]
//~^ ERROR `#[suggestion_part(...)]` is not a valid attribute
span2: Span,
#[applicability]
applicability: Applicability,
var: String,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute
struct BBa {
var: String,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
struct BBb {
#[suggestion_part]
//~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
span1: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
struct BBc {
#[suggestion_part()]
//~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
span1: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren)]
//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields
struct BC {
#[primary_span]
//~^ ERROR `#[primary_span]` is not a valid attribute
span: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren)]
struct BD {
#[suggestion_part]
//~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
span1: Span,
#[suggestion_part()]
//~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."`
span2: Span,
#[suggestion_part(foo = "bar")]
//~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute
span4: Span,
#[suggestion_part(code = "...")]
//~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
s1: String,
#[suggestion_part()]
//~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
s2: String,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
struct BE {
#[suggestion_part(code = "...", code = ",,,")]
//~^ ERROR specified multiple times
//~| NOTE previously specified here
span: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
struct BF {
#[suggestion_part(code = "(")]
first: Span,
#[suggestion_part(code = ")")]
second: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren)]
struct BG {
#[applicability]
appl: Applicability,
#[suggestion_part(code = "(")]
first: Span,
#[suggestion_part(code = ")")]
second: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
//~^ NOTE previously specified here
struct BH {
#[applicability]
//~^ ERROR specified multiple times
appl: Applicability,
#[suggestion_part(code = "(")]
first: Span,
#[suggestion_part(code = ")")]
second: Span,
}
#[derive(SessionSubdiagnostic)]
#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
struct BI {
#[suggestion_part(code = "")]
spans: Vec<Span>,
}

View File

@ -65,16 +65,16 @@ LL | #[label()]
| ^^^^^^^^^^
error: `code` is not a valid nested attribute of a `label` attribute
--> $DIR/subdiagnostic-derive.rs:137:1
--> $DIR/subdiagnostic-derive.rs:137:28
|
LL | #[label(parser::add_paren, code = "...")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error: `applicability` is not a valid nested attribute of a `label` attribute
--> $DIR/subdiagnostic-derive.rs:146:1
--> $DIR/subdiagnostic-derive.rs:146:28
|
LL | #[label(parser::add_paren, applicability = "machine-applicable")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive.rs:155:1
@ -100,13 +100,11 @@ error: `#[bar = ...]` is not a valid attribute
LL | #[bar = 4]
| ^^^^^^^^^^
error: `#[bar("...")]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:205:11
error: `#[bar(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:205:5
|
LL | #[bar("...")]
| ^^^^^
|
= help: first argument of the attribute should be the diagnostic slug
| ^^^^^^^^^^^^^
error: diagnostic slug must be first argument of a `#[label(...)]` attribute
--> $DIR/subdiagnostic-derive.rs:217:5
@ -163,6 +161,8 @@ error: `#[bar(...)]` is not a valid attribute
|
LL | #[bar("...")]
| ^^^^^^^^^^^^^
|
= help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
error: unexpected unsupported untagged union
--> $DIR/subdiagnostic-derive.rs:304:1
@ -175,19 +175,7 @@ LL | | }
| |_^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:314:1
|
LL | #[label(parser::add_paren)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:311:1
|
LL | #[label(parser::add_paren)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:314:1
--> $DIR/subdiagnostic-derive.rs:313:1
|
LL | #[label(parser::add_paren)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -199,7 +187,7 @@ LL | #[label(parser::add_paren)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(parser::add_paren)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:323:28
--> $DIR/subdiagnostic-derive.rs:321:28
|
LL | #[label(parser::add_paren, parser::add_paren)]
| ^^^^^^^^^^^^^^^^^
@ -207,134 +195,226 @@ LL | #[label(parser::add_paren, parser::add_paren)]
= help: a diagnostic slug must be the first argument to the attribute
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:336:5
--> $DIR/subdiagnostic-derive.rs:334:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:333:5
--> $DIR/subdiagnostic-derive.rs:331:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
error: subdiagnostic kind not specified
--> $DIR/subdiagnostic-derive.rs:342:8
--> $DIR/subdiagnostic-derive.rs:340:8
|
LL | struct AG {
| ^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:379:47
--> $DIR/subdiagnostic-derive.rs:377:47
|
LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
| ^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:379:33
--> $DIR/subdiagnostic-derive.rs:377:33
|
LL | #[suggestion(parser::add_paren, code = "...", code = "...")]
| ^^^^^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:397:5
--> $DIR/subdiagnostic-derive.rs:395:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:394:5
--> $DIR/subdiagnostic-derive.rs:392:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
--> $DIR/subdiagnostic-derive.rs:408:5
--> $DIR/subdiagnostic-derive.rs:405:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
error: suggestion without `applicability`
--> $DIR/subdiagnostic-derive.rs:403:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
LL | | struct AL {
LL | | #[primary_span]
... |
LL | | applicability: Span,
LL | | }
| |_^
error: suggestion without `applicability`
--> $DIR/subdiagnostic-derive.rs:414:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
LL | | struct AM {
LL | | #[primary_span]
LL | | span: Span,
LL | | }
| |_^
error: suggestion without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:422:1
--> $DIR/subdiagnostic-derive.rs:418:1
|
LL | / #[suggestion(parser::add_paren)]
LL | |
LL | | struct AN {
LL | | #[primary_span]
... |
LL | | applicability: Applicability,
LL | | }
| |_^
LL | #[suggestion(parser::add_paren)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: invalid applicability
--> $DIR/subdiagnostic-derive.rs:432:46
--> $DIR/subdiagnostic-derive.rs:428:46
|
LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")]
| ^^^^^^^^^^^^^^^^^^^^^
error: suggestion without `applicability`
--> $DIR/subdiagnostic-derive.rs:450:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
LL | |
LL | | struct AR {
LL | | var: String,
LL | | }
| |_^
error: suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:450:1
--> $DIR/subdiagnostic-derive.rs:446:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
LL | |
LL | | struct AR {
LL | | var: String,
LL | | }
| |_^
error: unsupported type attribute for subdiagnostic enum
--> $DIR/subdiagnostic-derive.rs:465:1
--> $DIR/subdiagnostic-derive.rs:460:1
|
LL | #[label]
| ^^^^^^^^
error: `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive.rs:485:39
--> $DIR/subdiagnostic-derive.rs:480:39
|
LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
| ^^^^^^^
error: `var` doesn't refer to a field on this type
--> $DIR/subdiagnostic-derive.rs:504:43
--> $DIR/subdiagnostic-derive.rs:499:43
|
LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")]
| ^^^^^^^
error: `#[suggestion_part]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:522:5
|
LL | #[suggestion_part]
| ^^^^^^^^^^^^^^^^^^
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
error: `#[suggestion_part(...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:525:5
|
LL | #[suggestion_part(code = "...")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[suggestion_part(...)]` is only valid in multipart suggestions
error: suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:519:1
|
LL | / #[suggestion(parser::add_paren, code = "...")]
LL | |
LL | | struct BA {
LL | | #[suggestion_part]
... |
LL | | var: String,
LL | | }
| |_^
error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute
--> $DIR/subdiagnostic-derive.rs:534:43
|
LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
| ^^^^^^^^^^^^
error: multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:534:1
|
LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")]
LL | |
LL | |
LL | | struct BBa {
LL | | var: String,
LL | | }
| |_^
error: `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:544:5
|
LL | #[suggestion_part]
| ^^^^^^^^^^^^^^^^^^
error: `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:552:5
|
LL | #[suggestion_part()]
| ^^^^^^^^^^^^^^^^^^^^
error: `#[primary_span]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:561:5
|
LL | #[primary_span]
| ^^^^^^^^^^^^^^^
|
= help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
error: multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:558:1
|
LL | / #[multipart_suggestion(parser::add_paren)]
LL | |
LL | | struct BC {
LL | | #[primary_span]
LL | |
LL | | span: Span,
LL | | }
| |_^
error: `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:569:5
|
LL | #[suggestion_part]
| ^^^^^^^^^^^^^^^^^^
error: `#[suggestion_part(...)]` attribute without `code = "..."`
--> $DIR/subdiagnostic-derive.rs:572:5
|
LL | #[suggestion_part()]
| ^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion_part(foo = ...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:575:23
|
LL | #[suggestion_part(foo = "bar")]
| ^^^^^^^^^^^
|
= help: `code` is the only valid nested attribute
error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive.rs:578:5
|
LL | #[suggestion_part(code = "...")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
--> $DIR/subdiagnostic-derive.rs:581:5
|
LL | #[suggestion_part()]
| ^^^^^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:589:37
|
LL | #[suggestion_part(code = "...", code = ",,,")]
| ^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:589:23
|
LL | #[suggestion_part(code = "...", code = ",,,")]
| ^^^^^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:619:5
|
LL | #[applicability]
| ^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:616:43
|
LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: cannot find attribute `foo` in this scope
--> $DIR/subdiagnostic-derive.rs:63:3
|
@ -395,6 +475,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
LL | #[label(slug)]
| ^^^^ not found in `rustc_errors::fluent`
error: aborting due to 52 previous errors
error: aborting due to 64 previous errors
For more information about this error, try `rustc --explain E0425`.

View File

@ -11,7 +11,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u8>>::bar::<'static, char>;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<'static, 'static, u8>>::bar::<'static, char>}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u8>>::bar::<'static, char>();
| ++
@ -29,7 +29,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<'static, 'static>>::bar::<'static, char>}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>();
| ++
@ -47,7 +47,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u8>>::baz;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<'static, 'static, u8>>::baz}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u8>>::baz();
| ++

View File

@ -11,7 +11,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u8>>::bar::<'static, char>;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::bar::<ReStatic, char>}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u8>>::bar::<'static, char>();
| ++
@ -29,7 +29,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u32>>::bar::<'static, char>();
| ++
@ -47,7 +47,7 @@ LL | let x: () = <i8 as Foo<'static, 'static, u8>>::baz;
|
= note: expected unit type `()`
found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::baz}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let x: () = <i8 as Foo<'static, 'static, u8>>::baz();
| ++

View File

@ -5,6 +5,11 @@ LL | if foo == y {}
| --- ^^ - _
| |
| for<'r> fn(&'r i32) -> &'r i32 {foo}
|
help: use parentheses to call this function
|
LL | if foo(/* &i32 */) == y {}
| ++++++++++++
error: aborting due to previous error

View File

@ -13,10 +13,10 @@ LL | trait NonObjectSafe1: Sized {}
| this trait cannot be made into an object...
error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
--> $DIR/feature-gate-object_safe_for_dispatch.rs:22:36
--> $DIR/feature-gate-object_safe_for_dispatch.rs:22:45
|
LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object
| ^^^^^^^^^^^^^^^^^^ `NonObjectSafe2` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/feature-gate-object_safe_for_dispatch.rs:7:8
@ -50,10 +50,10 @@ LL | fn foo<T>(&self);
= help: consider moving `foo` to another trait
error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
--> $DIR/feature-gate-object_safe_for_dispatch.rs:31:35
--> $DIR/feature-gate-object_safe_for_dispatch.rs:31:47
|
LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object
| ^^^^^^^^^^^^^^^^^^ `NonObjectSafe4` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/feature-gate-object_safe_for_dispatch.rs:15:22

View File

@ -6,14 +6,10 @@ LL | let x = f == g;
| |
| fn() {f}
|
help: you might have forgotten to call this function
help: use parentheses to call these
|
LL | let x = f() == g;
| ++
help: you might have forgotten to call this function
|
LL | let x = f == g();
| ++
LL | let x = f() == g();
| ++ ++
error[E0308]: mismatched types
--> $DIR/fn-compare-mismatch.rs:4:18

View File

@ -8,6 +8,10 @@ LL | let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
|
= note: expected unit type `()`
found struct `Box<dyn FnOnce(isize)>`
help: use parentheses to call this trait object
|
LL | let _: () = (Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>)(/* isize */);
| + ++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-trait-formatting.rs:10:17
@ -19,6 +23,10 @@ LL | let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>
|
= note: expected unit type `()`
found struct `Box<dyn Fn(isize, isize)>`
help: use parentheses to call this trait object
|
LL | let _: () = (Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>)(/* isize */, /* isize */);
| + +++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-trait-formatting.rs:14:17

View File

@ -1,16 +1,28 @@
// This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error.
struct Foo;
trait Bar {
//~^ NOTE `Bar` defines an item `bar`, perhaps you need to implement it
//~| NOTE `Bar` defines an item `bar`, perhaps you need to implement it
fn bar(&self) {}
}
impl Bar for Foo {}
fn main() {
let arc = std::sync::Arc::new(oops);
//~^ ERROR cannot find value `oops` in this scope
//~| NOTE not found
// The error "note: this is a function, perhaps you wish to call it" MUST NOT appear.
arc.blablabla();
//~^ ERROR no method named `blablabla`
arc.bar();
//~^ ERROR no method named `bar`
//~| NOTE method not found
let arc2 = std::sync::Arc::new(|| 1);
// The error "note: this is a function, perhaps you wish to call it" SHOULD appear
arc2.blablabla();
//~^ ERROR no method named `blablabla`
//~| HELP items from traits can only be used if the trait is implemented and in scope
let arc2 = std::sync::Arc::new(|| Foo);
arc2.bar();
//~^ ERROR no method named `bar`
//~| NOTE method not found
//~| NOTE this is a function, perhaps you wish to call it
//~| HELP items from traits can only be used if the trait is implemented and in scope
//~| HELP use parentheses to call this closure
}

View File

@ -1,22 +1,38 @@
error[E0425]: cannot find value `oops` in this scope
--> $DIR/fn-help-with-err.rs:3:35
--> $DIR/fn-help-with-err.rs:14:35
|
LL | let arc = std::sync::Arc::new(oops);
| ^^^^ not found in this scope
error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the current scope
--> $DIR/fn-help-with-err.rs:7:9
error[E0599]: no method named `bar` found for struct `Arc<_>` in the current scope
--> $DIR/fn-help-with-err.rs:17:9
|
LL | arc.blablabla();
| ^^^^^^^^^ method not found in `Arc<_>`
LL | arc.bar();
| ^^^ method not found in `Arc<_>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Bar` defines an item `bar`, perhaps you need to implement it
--> $DIR/fn-help-with-err.rs:5:1
|
LL | trait Bar {
| ^^^^^^^^^
error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>` in the current scope
--> $DIR/fn-help-with-err.rs:12:10
error[E0599]: no method named `bar` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>` in the current scope
--> $DIR/fn-help-with-err.rs:23:10
|
LL | arc2.blablabla();
| ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>`
| |
| this is a function, perhaps you wish to call it
LL | arc2.bar();
| ^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:22:36: 22:38]>`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Bar` defines an item `bar`, perhaps you need to implement it
--> $DIR/fn-help-with-err.rs:5:1
|
LL | trait Bar {
| ^^^^^^^^^
help: use parentheses to call this closure
|
LL | arc2().bar();
| ++
error: aborting due to 3 previous errors

View File

@ -21,10 +21,10 @@ LL | fn foo() -> Self where Self: Sized;
| +++++++++++++++++
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:13
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:28:17
|
LL | fn cat() -> Box<dyn NotObjectSafe> {
| ^^^^^^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
| ^^^^^^^^^^^^^^^^^ `NotObjectSafe` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-unsafe-trait-in-return-position-dyn-trait.rs:3:8

View File

@ -11,7 +11,7 @@ LL | fn opaque() -> impl Fn() -> i32 {
|
= note: expected type `i32`
found opaque type `impl Fn() -> i32`
help: use parentheses to call this closure
help: use parentheses to call this opaque type
|
LL | opaque()()
| ++

View File

@ -13,8 +13,8 @@ LL | fn test() -> Foo { Foo }
found fn item `fn(u32) -> Foo {Foo}`
help: use parentheses to instantiate this tuple struct
|
LL | fn test() -> Foo { Foo(_) }
| +++
LL | fn test() -> Foo { Foo(/* u32 */) }
| +++++++++++
error: aborting due to previous error

View File

@ -2,9 +2,7 @@ error[E0599]: no method named `f` found for fn pointer `fn(&u8)` in the current
--> $DIR/issue-57362-1.rs:20:7
|
LL | a.f();
| - ^ method not found in `fn(&u8)`
| |
| this is a function, perhaps you wish to call it
| ^ method not found in `fn(&u8)`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `Trait` defines an item `f`, perhaps you need to implement it

View File

@ -6,7 +6,7 @@ LL | foo > 12;
| |
| fn() -> i32 {foo}
|
help: you might have forgotten to call this function
help: use parentheses to call this function
|
LL | foo() > 12;
| ++
@ -28,10 +28,10 @@ LL | bar > 13;
| |
| fn(i64) -> i64 {bar}
|
help: you might have forgotten to call this function
help: use parentheses to call this function
|
LL | bar( /* arguments */ ) > 13;
| +++++++++++++++++++
LL | bar(/* i64 */) > 13;
| +++++++++++
error[E0308]: mismatched types
--> $DIR/issue-59488.rs:18:11
@ -50,14 +50,10 @@ LL | foo > foo;
| |
| fn() -> i32 {foo}
|
help: you might have forgotten to call this function
help: use parentheses to call these
|
LL | foo() > foo;
| ++
help: you might have forgotten to call this function
|
LL | foo > foo();
| ++
LL | foo() > foo();
| ++ ++
error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}`
--> $DIR/issue-59488.rs:25:9

View File

@ -8,11 +8,6 @@ LL | assert_eq!(a, 0);
| {integer}
|
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: you might have forgotten to call this function
--> $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
LL | if !(*left_val() == *right_val) {
| ++
error[E0308]: mismatched types
--> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5
@ -21,7 +16,7 @@ LL | assert_eq!(a, 0);
| ^^^^^^^^^^^^^^^^ expected fn item, found integer
|
= note: expected fn item `fn() -> i32 {a}`
found type `i32`
found type `{integer}`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `fn() -> i32 {a}` doesn't implement `Debug`

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-associated-consts.rs:12:30
--> $DIR/object-safety-associated-consts.rs:12:31
|
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-associated-consts.rs:9:11

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `X` cannot be made into an object
--> $DIR/object-safety-bounds.rs:7:11
--> $DIR/object-safety-bounds.rs:7:15
|
LL | fn f() -> Box<dyn X<U = u32>> {
| ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object
| ^^^^^^^^^^^^^^ `X` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-bounds.rs:4:13

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-generics.rs:18:30
--> $DIR/object-safety-generics.rs:18:31
|
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-generics.rs:10:8
@ -14,10 +14,10 @@ LL | fn bar<T>(&self, t: T);
= help: consider moving `bar` to another trait
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-generics.rs:24:39
--> $DIR/object-safety-generics.rs:24:40
|
LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-generics.rs:10:8

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-mentions-Self.rs:22:30
--> $DIR/object-safety-mentions-Self.rs:22:31
|
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-mentions-Self.rs:11:22
@ -14,10 +14,10 @@ LL | fn bar(&self, x: &Self);
= help: consider moving `bar` to another trait
error[E0038]: the trait `Baz` cannot be made into an object
--> $DIR/object-safety-mentions-Self.rs:28:30
--> $DIR/object-safety-mentions-Self.rs:28:31
|
LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
| ^^^^^^^^ `Baz` cannot be made into an object
| ^^^^^^^ `Baz` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-mentions-Self.rs:15:22

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/object-safety-no-static.rs:12:18
--> $DIR/object-safety-no-static.rs:12:22
|
LL | fn diverges() -> Box<dyn Foo> {
| ^^^^^^^^^^^^ `Foo` cannot be made into an object
| ^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-no-static.rs:9:8

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-sized-2.rs:14:30
--> $DIR/object-safety-sized-2.rs:14:31
|
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-sized-2.rs:9:18

View File

@ -1,8 +1,8 @@
error[E0038]: the trait `Bar` cannot be made into an object
--> $DIR/object-safety-sized.rs:12:30
--> $DIR/object-safety-sized.rs:12:31
|
LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
| ^^^^^^^^ `Bar` cannot be made into an object
| ^^^^^^^ `Bar` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety-sized.rs:8:13

View File

@ -329,8 +329,8 @@ LL | let _: Z = Z::Fn;
found fn item `fn(u8) -> Z {Z::Fn}`
help: use parentheses to instantiate this tuple variant
|
LL | let _: Z = Z::Fn(_);
| +++
LL | let _: Z = Z::Fn(/* u8 */);
| ++++++++++
error[E0618]: expected function, found enum variant `Z::Unit`
--> $DIR/privacy-enum-ctor.rs:31:17
@ -364,8 +364,8 @@ LL | let _: E = m::E::Fn;
found fn item `fn(u8) -> E {E::Fn}`
help: use parentheses to instantiate this tuple variant
|
LL | let _: E = m::E::Fn(_);
| +++
LL | let _: E = m::E::Fn(/* u8 */);
| ++++++++++
error[E0618]: expected function, found enum variant `m::E::Unit`
--> $DIR/privacy-enum-ctor.rs:47:16
@ -399,8 +399,8 @@ LL | let _: E = E::Fn;
found fn item `fn(u8) -> E {E::Fn}`
help: use parentheses to instantiate this tuple variant
|
LL | let _: E = E::Fn(_);
| +++
LL | let _: E = E::Fn(/* u8 */);
| ++++++++++
error[E0618]: expected function, found enum variant `E::Unit`
--> $DIR/privacy-enum-ctor.rs:55:16

View File

@ -0,0 +1,7 @@
fn main() {
let mut x = 1i32;
let y = Box::new(|| 1);
x = y;
//~^ ERROR mismatched types
//~| HELP use parentheses to call this closure
}

View File

@ -0,0 +1,20 @@
error[E0308]: mismatched types
--> $DIR/call-boxed.rs:4:9
|
LL | let mut x = 1i32;
| ---- expected due to this value
LL | let y = Box::new(|| 1);
| -- the found closure
LL | x = y;
| ^ expected `i32`, found struct `Box`
|
= note: expected type `i32`
found struct `Box<[closure@$DIR/call-boxed.rs:3:22: 3:24]>`
help: use parentheses to call this closure
|
LL | x = y();
| ++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,39 @@
struct Foo { i: i32 }
impl Foo {
fn bar(&self) {}
}
fn foo() -> Foo {
Foo { i: 1 }
}
fn main() {
foo.bar();
//~^ ERROR no method named `bar`
//~| HELP use parentheses to call this function
foo.i;
//~^ ERROR no field `i`
//~| HELP use parentheses to call this function
let callable = Box::new(|| Foo { i: 1 }) as Box<dyn Fn() -> Foo>;
callable.bar();
//~^ ERROR no method named `bar`
//~| HELP use parentheses to call this trait object
callable.i;
//~^ ERROR no field `i`
//~| HELP use parentheses to call this trait object
}
fn type_param<T: Fn() -> Foo>(t: T) {
t.bar();
//~^ ERROR no method named `bar`
//~| HELP use parentheses to call this type parameter
t.i;
//~^ ERROR no field `i`
//~| HELP use parentheses to call this type parameter
}

View File

@ -0,0 +1,75 @@
error[E0599]: no method named `bar` found for fn item `fn() -> Foo {foo}` in the current scope
--> $DIR/call-on-missing.rs:12:9
|
LL | foo.bar();
| ^^^ method not found in `fn() -> Foo {foo}`
|
help: use parentheses to call this function
|
LL | foo().bar();
| ++
error[E0609]: no field `i` on type `fn() -> Foo {foo}`
--> $DIR/call-on-missing.rs:16:9
|
LL | foo.i;
| ^
|
help: use parentheses to call this function
|
LL | foo().i;
| ++
error[E0599]: no method named `bar` found for struct `Box<dyn Fn() -> Foo>` in the current scope
--> $DIR/call-on-missing.rs:22:14
|
LL | callable.bar();
| ^^^ method not found in `Box<dyn Fn() -> Foo>`
|
help: use parentheses to call this trait object
|
LL | callable().bar();
| ++
error[E0609]: no field `i` on type `Box<dyn Fn() -> Foo>`
--> $DIR/call-on-missing.rs:26:14
|
LL | callable.i;
| ^ unknown field
|
help: use parentheses to call this trait object
|
LL | callable().i;
| ++
error[E0599]: no method named `bar` found for type parameter `T` in the current scope
--> $DIR/call-on-missing.rs:32:7
|
LL | fn type_param<T: Fn() -> Foo>(t: T) {
| - method `bar` not found for this type parameter
LL | t.bar();
| ^^^ method not found in `T`
|
help: use parentheses to call this type parameter
|
LL | t().bar();
| ++
error[E0609]: no field `i` on type `T`
--> $DIR/call-on-missing.rs:36:7
|
LL | fn type_param<T: Fn() -> Foo>(t: T) {
| - type parameter 'T' declared here
...
LL | t.i;
| ^
|
help: use parentheses to call this type parameter
|
LL | t().i;
| ++
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0599, E0609.
For more information about an error, try `rustc --explain E0599`.

View File

@ -33,8 +33,8 @@ LL | let _: usize = foo;
found fn item `fn(usize, usize) -> usize {foo}`
help: use parentheses to call this function
|
LL | let _: usize = foo(_, _);
| ++++++
LL | let _: usize = foo(/* usize */, /* usize */);
| ++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:30:16
@ -51,8 +51,8 @@ LL | let _: S = S;
found fn item `fn(usize, usize) -> S {S}`
help: use parentheses to instantiate this tuple struct
|
LL | let _: S = S(_, _);
| ++++++
LL | let _: S = S(/* usize */, /* usize */);
| ++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:31:20
@ -103,10 +103,10 @@ LL | let _: usize = T::baz;
|
= note: expected type `usize`
found fn item `fn(usize, usize) -> usize {<_ as T>::baz}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = T::baz(_, _);
| ++++++
LL | let _: usize = T::baz(/* usize */, /* usize */);
| ++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:34:20
@ -121,10 +121,10 @@ LL | let _: usize = T::bat;
|
= note: expected type `usize`
found fn item `fn(usize) -> usize {<_ as T>::bat}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = T::bat(_);
| +++
LL | let _: usize = T::bat(/* usize */);
| +++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:35:16
@ -141,8 +141,8 @@ LL | let _: E = E::A;
found fn item `fn(usize) -> E {E::A}`
help: use parentheses to instantiate this tuple variant
|
LL | let _: E = E::A(_);
| +++
LL | let _: E = E::A(/* usize */);
| +++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:37:20
@ -157,10 +157,10 @@ LL | let _: usize = X::baz;
|
= note: expected type `usize`
found fn item `fn(usize, usize) -> usize {<X as T>::baz}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::baz(_, _);
| ++++++
LL | let _: usize = X::baz(/* usize */, /* usize */);
| ++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:38:20
@ -175,10 +175,10 @@ LL | let _: usize = X::bat;
|
= note: expected type `usize`
found fn item `fn(usize) -> usize {<X as T>::bat}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::bat(_);
| +++
LL | let _: usize = X::bat(/* usize */);
| +++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:39:20
@ -193,10 +193,10 @@ LL | let _: usize = X::bax;
|
= note: expected type `usize`
found fn item `fn(usize) -> usize {<X as T>::bax}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::bax(_);
| +++
LL | let _: usize = X::bax(/* usize */);
| +++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:40:20
@ -211,10 +211,10 @@ LL | let _: usize = X::bach;
|
= note: expected type `usize`
found fn item `fn(usize) -> usize {<X as T>::bach}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::bach(_);
| +++
LL | let _: usize = X::bach(/* usize */);
| +++++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:41:20
@ -229,10 +229,10 @@ LL | let _: usize = X::ban;
|
= note: expected type `usize`
found fn item `for<'r> fn(&'r X) -> usize {<X as T>::ban}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::ban(_);
| +++
LL | let _: usize = X::ban(/* &X */);
| ++++++++++
error[E0308]: mismatched types
--> $DIR/fn-or-tuple-struct-without-args.rs:42:20
@ -247,10 +247,10 @@ LL | let _: usize = X::bal;
|
= note: expected type `usize`
found fn item `for<'r> fn(&'r X) -> usize {<X as T>::bal}`
help: use parentheses to call this function
help: use parentheses to call this associated function
|
LL | let _: usize = X::bal(_);
| +++
LL | let _: usize = X::bal(/* &X */);
| ++++++++++
error[E0615]: attempted to take value of method `ban` on type `X`
--> $DIR/fn-or-tuple-struct-without-args.rs:43:22

View File

@ -1,8 +1,8 @@
error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
--> $DIR/type-check-defaults.rs:6:19
--> $DIR/type-check-defaults.rs:6:23
|
LL | struct WellFormed<Z = Foo<i32, i32>>(Z);
| ^^^^^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
| ^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
|
= help: the trait `FromIterator<i32>` is not implemented for `i32`
note: required by a bound in `Foo`
@ -12,10 +12,10 @@ LL | struct Foo<T, U: FromIterator<T>>(T, U);
| ^^^^^^^^^^^^^^^ required by this bound in `Foo`
error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32`
--> $DIR/type-check-defaults.rs:8:27
--> $DIR/type-check-defaults.rs:8:38
|
LL | struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
| ^^^^^^^^^^^^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
| ^^^^^^^^^^^^^ value of type `i32` cannot be built from `std::iter::Iterator<Item=i32>`
|
= help: the trait `FromIterator<i32>` is not implemented for `i32`
note: required by a bound in `Foo`

View File

@ -2,17 +2,13 @@ error[E0599]: no method named `x` found for fn item `fn() -> Ret {Obj::func}` in
--> $DIR/issue-29124.rs:15:15
|
LL | Obj::func.x();
| --------- ^ method not found in `fn() -> Ret {Obj::func}`
| |
| this is a function, perhaps you wish to call it
| ^ method not found in `fn() -> Ret {Obj::func}`
error[E0599]: no method named `x` found for fn item `fn() -> Ret {func}` in the current scope
--> $DIR/issue-29124.rs:17:10
|
LL | func.x();
| ---- ^ method not found in `fn() -> Ret {func}`
| |
| this is a function, perhaps you wish to call it
| ^ method not found in `fn() -> Ret {func}`
error: aborting due to 2 previous errors

View File

@ -4,7 +4,7 @@ struct Bar<T> {
struct Foo();
impl Foo {
fn foo() { }
fn foo(&self) { }
}
fn main() {

View File

@ -2,11 +2,9 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the
--> $DIR/empty-tuple-method.rs:12:15
|
LL | thing.bar.foo();
| --------- ^^^ method not found in `fn() -> Foo {Foo}`
| |
| this is the constructor of a struct
| ^^^ method not found in `fn() -> Foo {Foo}`
|
help: call the constructor
help: use parentheses to instantiate this tuple struct
|
LL | (thing.bar)().foo();
| + +++

View File

@ -6,7 +6,7 @@ enum Foo{
Tup()
}
impl Foo {
fn foo() { }
fn foo(&self) { }
}
fn main() {

View File

@ -2,11 +2,9 @@ error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` i
--> $DIR/enum-variant.rs:14:15
|
LL | thing.bar.foo();
| --------- ^^^ method not found in `fn() -> Foo {Foo::Tup}`
| |
| this is the constructor of an enum variant
| ^^^ method not found in `fn() -> Foo {Foo::Tup}`
|
help: call the constructor
help: use parentheses to instantiate this tuple variant
|
LL | (thing.bar)().foo();
| + +++

View File

@ -2,14 +2,12 @@ error[E0609]: no field `0` on type `fn(char, u16) -> Foo {Foo}`
--> $DIR/tuple-field.rs:12:15
|
LL | thing.bar.0;
| --------- ^
| |
| this is the constructor of a struct
| ^
|
help: call the constructor
help: use parentheses to instantiate this tuple struct
|
LL | (thing.bar)(_, _).0;
| + +++++++
LL | (thing.bar)(/* char */, /* u16 */).0;
| + ++++++++++++++++++++++++
error: aborting due to previous error

View File

@ -2,14 +2,7 @@ error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}`
--> $DIR/tuple-method.rs:12:15
|
LL | thing.bar.foo();
| --------- ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
| |
| this is the constructor of a struct
|
help: call the constructor
|
LL | (thing.bar)(_, _).foo();
| + +++++++
| ^^^ method not found in `fn(u8, i32) -> Foo {Foo}`
error: aborting due to previous error

View File

@ -2,27 +2,13 @@ error[E0599]: no method named `nonexistent_method` found for fn item `fn(_) -> O
--> $DIR/issue-96738.rs:2:10
|
LL | Some.nonexistent_method();
| ---- ^^^^^^^^^^^^^^^^^^ method not found in `fn(_) -> Option<_> {Option::<_>::Some}`
| |
| this is the constructor of an enum variant
|
help: call the constructor
|
LL | (Some)(_).nonexistent_method();
| + ++++
| ^^^^^^^^^^^^^^^^^^ method not found in `fn(_) -> Option<_> {Option::<_>::Some}`
error[E0609]: no field `nonexistent_field` on type `fn(_) -> Option<_> {Option::<_>::Some}`
--> $DIR/issue-96738.rs:3:10
|
LL | Some.nonexistent_field;
| ---- ^^^^^^^^^^^^^^^^^
| |
| this is the constructor of an enum variant
|
help: call the constructor
|
LL | (Some)(_).nonexistent_field;
| + ++++
| ^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -2,9 +2,7 @@ error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-cl
--> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
|
LL | mut_.call((0, ));
| ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
| |
| this is a function, perhaps you wish to call it
| ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
error: aborting due to previous error

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `Self: Eq` is not satisfied
--> $DIR/wf-trait-fn-ret.rs:10:22
--> $DIR/wf-trait-fn-ret.rs:10:23
|
LL | fn bar(&self) -> &Bar<Self>;
| ^^^^^^^^^^ the trait `Eq` is not implemented for `Self`
| ^^^^^^^^^ the trait `Eq` is not implemented for `Self`
|
note: required by a bound in `Bar`
--> $DIR/wf-trait-fn-ret.rs:7:14