mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 19:58:32 +00:00
Auto merge of #100920 - Dylan-DPC:rollup-vlcw3sr, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #99249 (Do not re-parse function signatures to suggest generics) - #100309 (Extend comma suggestion to cases where fields arent missing) - #100368 (InferCtxt tainted_by_errors_flag should be Option<ErrorGuaranteed>) - #100768 (Migrate `rustc_plugin_impl` to `SessionDiagnostic`) - #100835 (net listen backlog update, follow-up from #97963.) - #100851 (Fix rustc_parse_format precision & width spans) - #100857 (Refactor query modifier parsing) - #100907 (Fix typo in UnreachableProp) - #100909 (Minor `ast::LitKind` improvements) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
a1bea1551b
@ -4321,6 +4321,7 @@ dependencies = [
|
|||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_lint",
|
"rustc_lint",
|
||||||
|
"rustc_macros",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
|
@ -1751,7 +1751,8 @@ pub enum LitFloatType {
|
|||||||
/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
|
/// E.g., `"foo"`, `42`, `12.34`, or `bool`.
|
||||||
#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
|
#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq, HashStable_Generic)]
|
||||||
pub enum LitKind {
|
pub enum LitKind {
|
||||||
/// A string literal (`"foo"`).
|
/// A string literal (`"foo"`). The symbol is unescaped, and so may differ
|
||||||
|
/// from the original token's symbol.
|
||||||
Str(Symbol, StrStyle),
|
Str(Symbol, StrStyle),
|
||||||
/// A byte string (`b"foo"`).
|
/// A byte string (`b"foo"`).
|
||||||
ByteStr(Lrc<[u8]>),
|
ByteStr(Lrc<[u8]>),
|
||||||
@ -1761,12 +1762,13 @@ pub enum LitKind {
|
|||||||
Char(char),
|
Char(char),
|
||||||
/// An integer literal (`1`).
|
/// An integer literal (`1`).
|
||||||
Int(u128, LitIntType),
|
Int(u128, LitIntType),
|
||||||
/// A float literal (`1f64` or `1E10f64`).
|
/// A float literal (`1f64` or `1E10f64`). Stored as a symbol rather than
|
||||||
|
/// `f64` so that `LitKind` can impl `Eq` and `Hash`.
|
||||||
Float(Symbol, LitFloatType),
|
Float(Symbol, LitFloatType),
|
||||||
/// A boolean literal.
|
/// A boolean literal.
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
/// Placeholder for a literal that wasn't well-formed in some way.
|
/// Placeholder for a literal that wasn't well-formed in some way.
|
||||||
Err(Symbol),
|
Err,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LitKind {
|
impl LitKind {
|
||||||
@ -1805,7 +1807,7 @@ impl LitKind {
|
|||||||
| LitKind::Int(_, LitIntType::Unsuffixed)
|
| LitKind::Int(_, LitIntType::Unsuffixed)
|
||||||
| LitKind::Float(_, LitFloatType::Unsuffixed)
|
| LitKind::Float(_, LitFloatType::Unsuffixed)
|
||||||
| LitKind::Bool(..)
|
| LitKind::Bool(..)
|
||||||
| LitKind::Err(..) => false,
|
| LitKind::Err => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ impl LitKind {
|
|||||||
|
|
||||||
LitKind::ByteStr(bytes.into())
|
LitKind::ByteStr(bytes.into())
|
||||||
}
|
}
|
||||||
token::Err => LitKind::Err(symbol),
|
token::Err => LitKind::Err,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ impl LitKind {
|
|||||||
let symbol = if value { kw::True } else { kw::False };
|
let symbol = if value { kw::True } else { kw::False };
|
||||||
(token::Bool, symbol, None)
|
(token::Bool, symbol, None)
|
||||||
}
|
}
|
||||||
LitKind::Err(symbol) => (token::Err, symbol, None),
|
LitKind::Err => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
token::Lit::new(kind, symbol, suffix)
|
token::Lit::new(kind, symbol, suffix)
|
||||||
|
@ -928,7 +928,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
} else {
|
} else {
|
||||||
Lit {
|
Lit {
|
||||||
token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
|
token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None),
|
||||||
kind: LitKind::Err(kw::Empty),
|
kind: LitKind::Err,
|
||||||
span: DUMMY_SP,
|
span: DUMMY_SP,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -39,7 +39,7 @@ pub fn expand_concat(
|
|||||||
ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => {
|
ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => {
|
||||||
cx.span_err(e.span, "cannot concatenate a byte string literal");
|
cx.span_err(e.span, "cannot concatenate a byte string literal");
|
||||||
}
|
}
|
||||||
ast::LitKind::Err(_) => {
|
ast::LitKind::Err => {
|
||||||
has_errors = true;
|
has_errors = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -42,7 +42,7 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
|
|||||||
ast::LitKind::Bool(_) => {
|
ast::LitKind::Bool(_) => {
|
||||||
cx.span_err(expr.span, "cannot concatenate boolean literals");
|
cx.span_err(expr.span, "cannot concatenate boolean literals");
|
||||||
}
|
}
|
||||||
ast::LitKind::Err(_) => {}
|
ast::LitKind::Err => {}
|
||||||
ast::LitKind::Int(_, _) if !is_nested => {
|
ast::LitKind::Int(_, _) if !is_nested => {
|
||||||
let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
|
let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals");
|
||||||
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
|
if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) {
|
||||||
|
@ -413,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
/// Verifies one piece of a parse string, and remembers it if valid.
|
/// Verifies one piece of a parse string, and remembers it if valid.
|
||||||
/// All errors are not emitted as fatal so we can continue giving errors
|
/// All errors are not emitted as fatal so we can continue giving errors
|
||||||
/// about this and possibly other format strings.
|
/// about this and possibly other format strings.
|
||||||
fn verify_piece(&mut self, p: &parse::Piece<'_>) {
|
fn verify_piece(&mut self, p: &parse::Piece<'a>) {
|
||||||
match *p {
|
match *p {
|
||||||
parse::String(..) => {}
|
parse::String(..) => {}
|
||||||
parse::NextArgument(ref arg) => {
|
parse::NextArgument(ref arg) => {
|
||||||
@ -433,6 +433,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
let has_precision = arg.format.precision != Count::CountImplied;
|
let has_precision = arg.format.precision != Count::CountImplied;
|
||||||
let has_width = arg.format.width != Count::CountImplied;
|
let has_width = arg.format.width != Count::CountImplied;
|
||||||
|
|
||||||
|
if has_precision || has_width {
|
||||||
|
// push before named params are resolved to aid diagnostics
|
||||||
|
self.arg_with_formatting.push(arg.format);
|
||||||
|
}
|
||||||
|
|
||||||
// argument second, if it's an implicit positional parameter
|
// argument second, if it's an implicit positional parameter
|
||||||
// it's written second, so it should come after width/precision.
|
// it's written second, so it should come after width/precision.
|
||||||
let pos = match arg.position {
|
let pos = match arg.position {
|
||||||
@ -581,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
let mut zero_based_note = false;
|
let mut zero_based_note = false;
|
||||||
|
|
||||||
let count = self.pieces.len()
|
let count = self.pieces.len()
|
||||||
+ self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
|
+ self
|
||||||
|
.arg_with_formatting
|
||||||
|
.iter()
|
||||||
|
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
|
||||||
|
.count();
|
||||||
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
|
if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
|
||||||
e = self.ecx.struct_span_err(
|
e = self.ecx.struct_span_err(
|
||||||
sp,
|
sp,
|
||||||
@ -647,7 +656,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
+ self
|
+ self
|
||||||
.arg_with_formatting
|
.arg_with_formatting
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|fmt| fmt.precision_span.is_some())
|
.filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_)))
|
||||||
.count();
|
.count();
|
||||||
e.span_label(
|
e.span_label(
|
||||||
span,
|
span,
|
||||||
@ -899,26 +908,22 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
},
|
},
|
||||||
position_span: arg.position_span,
|
position_span: arg.position_span,
|
||||||
format: parse::FormatSpec {
|
format: parse::FormatSpec {
|
||||||
fill: arg.format.fill,
|
fill: None,
|
||||||
align: parse::AlignUnknown,
|
align: parse::AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: parse::CountImplied,
|
precision: parse::CountImplied,
|
||||||
precision_span: None,
|
precision_span: arg.format.precision_span,
|
||||||
width: parse::CountImplied,
|
width: parse::CountImplied,
|
||||||
width_span: None,
|
width_span: arg.format.width_span,
|
||||||
ty: arg.format.ty,
|
ty: arg.format.ty,
|
||||||
ty_span: arg.format.ty_span,
|
ty_span: arg.format.ty_span,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let fill = arg.format.fill.unwrap_or(' ');
|
let fill = arg.format.fill.unwrap_or(' ');
|
||||||
|
|
||||||
let pos_simple = arg.position.index() == simple_arg.position.index();
|
let pos_simple = arg.position.index() == simple_arg.position.index();
|
||||||
|
|
||||||
if arg.format.precision_span.is_some() || arg.format.width_span.is_some() {
|
if !pos_simple || arg.format != simple_arg.format {
|
||||||
self.arg_with_formatting.push(arg.format);
|
|
||||||
}
|
|
||||||
if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
|
|
||||||
self.all_pieces_simple = false;
|
self.all_pieces_simple = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
plugin_impl_load_plugin_error = {$msg}
|
||||||
|
|
||||||
|
plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute
|
||||||
|
.label = malformed attribute
|
@ -41,6 +41,7 @@ fluent_messages! {
|
|||||||
lint => "../locales/en-US/lint.ftl",
|
lint => "../locales/en-US/lint.ftl",
|
||||||
parser => "../locales/en-US/parser.ftl",
|
parser => "../locales/en-US/parser.ftl",
|
||||||
passes => "../locales/en-US/passes.ftl",
|
passes => "../locales/en-US/passes.ftl",
|
||||||
|
plugin_impl => "../locales/en-US/plugin_impl.ftl",
|
||||||
privacy => "../locales/en-US/privacy.ftl",
|
privacy => "../locales/en-US/privacy.ftl",
|
||||||
typeck => "../locales/en-US/typeck.ftl",
|
typeck => "../locales/en-US/typeck.ftl",
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1227,7 @@ pub fn expr_to_spanned_string<'a>(
|
|||||||
);
|
);
|
||||||
Some((err, true))
|
Some((err, true))
|
||||||
}
|
}
|
||||||
ast::LitKind::Err(_) => None,
|
ast::LitKind::Err => None,
|
||||||
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
|
_ => Some((cx.struct_span_err(l.span, err_msg), false)),
|
||||||
},
|
},
|
||||||
ast::ExprKind::Err => None,
|
ast::ExprKind::Err => None,
|
||||||
|
@ -74,7 +74,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
evaluation_cache: self.evaluation_cache.clone(),
|
evaluation_cache: self.evaluation_cache.clone(),
|
||||||
reported_trait_errors: self.reported_trait_errors.clone(),
|
reported_trait_errors: self.reported_trait_errors.clone(),
|
||||||
reported_closure_mismatch: self.reported_closure_mismatch.clone(),
|
reported_closure_mismatch: self.reported_closure_mismatch.clone(),
|
||||||
tainted_by_errors_flag: self.tainted_by_errors_flag.clone(),
|
tainted_by_errors: self.tainted_by_errors.clone(),
|
||||||
err_count_on_creation: self.err_count_on_creation,
|
err_count_on_creation: self.err_count_on_creation,
|
||||||
in_snapshot: self.in_snapshot.clone(),
|
in_snapshot: self.in_snapshot.clone(),
|
||||||
universe: self.universe.clone(),
|
universe: self.universe.clone(),
|
||||||
|
@ -32,7 +32,7 @@ pub use rustc_middle::ty::IntVarValue;
|
|||||||
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
|
use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
|
use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::Span;
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use std::cell::{Cell, Ref, RefCell};
|
use std::cell::{Cell, Ref, RefCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -316,12 +316,12 @@ pub struct InferCtxt<'a, 'tcx> {
|
|||||||
///
|
///
|
||||||
/// Don't read this flag directly, call `is_tainted_by_errors()`
|
/// Don't read this flag directly, call `is_tainted_by_errors()`
|
||||||
/// and `set_tainted_by_errors()`.
|
/// and `set_tainted_by_errors()`.
|
||||||
tainted_by_errors_flag: Cell<bool>,
|
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
|
||||||
|
|
||||||
/// Track how many errors were reported when this infcx is created.
|
/// Track how many errors were reported when this infcx is created.
|
||||||
/// If the number of errors increases, that's also a sign (line
|
/// If the number of errors increases, that's also a sign (line
|
||||||
/// `tainted_by_errors`) to avoid reporting certain kinds of errors.
|
/// `tainted_by_errors`) to avoid reporting certain kinds of errors.
|
||||||
// FIXME(matthewjasper) Merge into `tainted_by_errors_flag`
|
// FIXME(matthewjasper) Merge into `tainted_by_errors`
|
||||||
err_count_on_creation: usize,
|
err_count_on_creation: usize,
|
||||||
|
|
||||||
/// This flag is true while there is an active snapshot.
|
/// This flag is true while there is an active snapshot.
|
||||||
@ -624,7 +624,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
|
|||||||
evaluation_cache: Default::default(),
|
evaluation_cache: Default::default(),
|
||||||
reported_trait_errors: Default::default(),
|
reported_trait_errors: Default::default(),
|
||||||
reported_closure_mismatch: Default::default(),
|
reported_closure_mismatch: Default::default(),
|
||||||
tainted_by_errors_flag: Cell::new(false),
|
tainted_by_errors: Cell::new(None),
|
||||||
err_count_on_creation: tcx.sess.err_count(),
|
err_count_on_creation: tcx.sess.err_count(),
|
||||||
in_snapshot: Cell::new(false),
|
in_snapshot: Cell::new(false),
|
||||||
skip_leak_check: Cell::new(false),
|
skip_leak_check: Cell::new(false),
|
||||||
@ -1227,23 +1227,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||||||
pub fn is_tainted_by_errors(&self) -> bool {
|
pub fn is_tainted_by_errors(&self) -> bool {
|
||||||
debug!(
|
debug!(
|
||||||
"is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
|
"is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
|
||||||
tainted_by_errors_flag={})",
|
tainted_by_errors={})",
|
||||||
self.tcx.sess.err_count(),
|
self.tcx.sess.err_count(),
|
||||||
self.err_count_on_creation,
|
self.err_count_on_creation,
|
||||||
self.tainted_by_errors_flag.get()
|
self.tainted_by_errors.get().is_some()
|
||||||
);
|
);
|
||||||
|
|
||||||
if self.tcx.sess.err_count() > self.err_count_on_creation {
|
if self.tcx.sess.err_count() > self.err_count_on_creation {
|
||||||
return true; // errors reported since this infcx was made
|
return true; // errors reported since this infcx was made
|
||||||
}
|
}
|
||||||
self.tainted_by_errors_flag.get()
|
self.tainted_by_errors.get().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the "tainted by errors" flag to true. We call this when we
|
/// Set the "tainted by errors" flag to true. We call this when we
|
||||||
/// observe an error from a prior pass.
|
/// observe an error from a prior pass.
|
||||||
pub fn set_tainted_by_errors(&self) {
|
pub fn set_tainted_by_errors(&self) {
|
||||||
debug!("set_tainted_by_errors()");
|
debug!("set_tainted_by_errors()");
|
||||||
self.tainted_by_errors_flag.set(true)
|
self.tainted_by_errors.set(Some(
|
||||||
|
self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip_region_resolution(&self) {
|
pub fn skip_region_resolution(&self) {
|
||||||
|
@ -1,139 +1,17 @@
|
|||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Delimiter, TokenTree};
|
|
||||||
use quote::{quote, quote_spanned};
|
use quote::{quote, quote_spanned};
|
||||||
use syn::parse::{Parse, ParseStream, Result};
|
use syn::parse::{Parse, ParseStream, Result};
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{
|
||||||
braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error,
|
braced, parenthesized, parse_macro_input, parse_quote, token, AttrStyle, Attribute, Block,
|
||||||
Expr, Ident, ReturnType, Token, Type,
|
Error, Expr, Ident, Pat, ReturnType, Token, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod kw {
|
mod kw {
|
||||||
syn::custom_keyword!(query);
|
syn::custom_keyword!(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ident or a wildcard `_`.
|
|
||||||
struct IdentOrWild(Ident);
|
|
||||||
|
|
||||||
impl Parse for IdentOrWild {
|
|
||||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
|
||||||
Ok(if input.peek(Token![_]) {
|
|
||||||
let underscore = input.parse::<Token![_]>()?;
|
|
||||||
IdentOrWild(Ident::new("_", underscore.span()))
|
|
||||||
} else {
|
|
||||||
IdentOrWild(input.parse()?)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A modifier for a query
|
|
||||||
enum QueryModifier {
|
|
||||||
/// The description of the query.
|
|
||||||
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
|
|
||||||
|
|
||||||
/// Use this type for the in-memory cache.
|
|
||||||
Storage(Type),
|
|
||||||
|
|
||||||
/// Cache the query to disk if the `Expr` returns true.
|
|
||||||
Cache(Option<IdentOrWild>, Block),
|
|
||||||
|
|
||||||
/// Custom code to load the query from disk.
|
|
||||||
LoadCached(Ident, Ident, Block),
|
|
||||||
|
|
||||||
/// A cycle error for this query aborting the compilation with a fatal error.
|
|
||||||
FatalCycle(Ident),
|
|
||||||
|
|
||||||
/// A cycle error results in a delay_bug call
|
|
||||||
CycleDelayBug(Ident),
|
|
||||||
|
|
||||||
/// Don't hash the result, instead just mark a query red if it runs
|
|
||||||
NoHash(Ident),
|
|
||||||
|
|
||||||
/// Generate a dep node based on the dependencies of the query
|
|
||||||
Anon(Ident),
|
|
||||||
|
|
||||||
/// Always evaluate the query, ignoring its dependencies
|
|
||||||
EvalAlways(Ident),
|
|
||||||
|
|
||||||
/// Use a separate query provider for local and extern crates
|
|
||||||
SeparateProvideExtern(Ident),
|
|
||||||
|
|
||||||
/// Always remap the ParamEnv's constness before hashing and passing to the query provider
|
|
||||||
RemapEnvConstness(Ident),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for QueryModifier {
|
|
||||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
|
||||||
let modifier: Ident = input.parse()?;
|
|
||||||
if modifier == "desc" {
|
|
||||||
// Parse a description modifier like:
|
|
||||||
// `desc { |tcx| "foo {}", tcx.item_path(key) }`
|
|
||||||
let attr_content;
|
|
||||||
braced!(attr_content in input);
|
|
||||||
let tcx = if attr_content.peek(Token![|]) {
|
|
||||||
attr_content.parse::<Token![|]>()?;
|
|
||||||
let tcx = attr_content.parse()?;
|
|
||||||
attr_content.parse::<Token![|]>()?;
|
|
||||||
Some(tcx)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let desc = attr_content.parse_terminated(Expr::parse)?;
|
|
||||||
Ok(QueryModifier::Desc(tcx, desc))
|
|
||||||
} else if modifier == "cache_on_disk_if" {
|
|
||||||
// Parse a cache modifier like:
|
|
||||||
// `cache(tcx, value) { |tcx| key.is_local() }`
|
|
||||||
let has_args = if let TokenTree::Group(group) = input.fork().parse()? {
|
|
||||||
group.delimiter() == Delimiter::Parenthesis
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
let args = if has_args {
|
|
||||||
let args;
|
|
||||||
parenthesized!(args in input);
|
|
||||||
let tcx = args.parse()?;
|
|
||||||
Some(tcx)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let block = input.parse()?;
|
|
||||||
Ok(QueryModifier::Cache(args, block))
|
|
||||||
} else if modifier == "load_cached" {
|
|
||||||
// Parse a load_cached modifier like:
|
|
||||||
// `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }`
|
|
||||||
let args;
|
|
||||||
parenthesized!(args in input);
|
|
||||||
let tcx = args.parse()?;
|
|
||||||
args.parse::<Token![,]>()?;
|
|
||||||
let id = args.parse()?;
|
|
||||||
let block = input.parse()?;
|
|
||||||
Ok(QueryModifier::LoadCached(tcx, id, block))
|
|
||||||
} else if modifier == "storage" {
|
|
||||||
let args;
|
|
||||||
parenthesized!(args in input);
|
|
||||||
let ty = args.parse()?;
|
|
||||||
Ok(QueryModifier::Storage(ty))
|
|
||||||
} else if modifier == "fatal_cycle" {
|
|
||||||
Ok(QueryModifier::FatalCycle(modifier))
|
|
||||||
} else if modifier == "cycle_delay_bug" {
|
|
||||||
Ok(QueryModifier::CycleDelayBug(modifier))
|
|
||||||
} else if modifier == "no_hash" {
|
|
||||||
Ok(QueryModifier::NoHash(modifier))
|
|
||||||
} else if modifier == "anon" {
|
|
||||||
Ok(QueryModifier::Anon(modifier))
|
|
||||||
} else if modifier == "eval_always" {
|
|
||||||
Ok(QueryModifier::EvalAlways(modifier))
|
|
||||||
} else if modifier == "separate_provide_extern" {
|
|
||||||
Ok(QueryModifier::SeparateProvideExtern(modifier))
|
|
||||||
} else if modifier == "remap_env_constness" {
|
|
||||||
Ok(QueryModifier::RemapEnvConstness(modifier))
|
|
||||||
} else {
|
|
||||||
Err(Error::new(modifier.span(), "unknown query modifier"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensures only doc comment attributes are used
|
/// Ensures only doc comment attributes are used
|
||||||
fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
|
fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
|
||||||
let inner = |attr: Attribute| {
|
let inner = |attr: Attribute| {
|
||||||
@ -154,16 +32,16 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<Vec<Attribute>> {
|
|||||||
/// A compiler query. `query ... { ... }`
|
/// A compiler query. `query ... { ... }`
|
||||||
struct Query {
|
struct Query {
|
||||||
doc_comments: Vec<Attribute>,
|
doc_comments: Vec<Attribute>,
|
||||||
modifiers: List<QueryModifier>,
|
modifiers: QueryModifiers,
|
||||||
name: Ident,
|
name: Ident,
|
||||||
key: IdentOrWild,
|
key: Pat,
|
||||||
arg: Type,
|
arg: Type,
|
||||||
result: ReturnType,
|
result: ReturnType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Query {
|
impl Parse for Query {
|
||||||
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
fn parse(input: ParseStream<'_>) -> Result<Self> {
|
||||||
let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?;
|
let mut doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?;
|
||||||
|
|
||||||
// Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>`
|
// Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>`
|
||||||
input.parse::<kw::query>()?;
|
input.parse::<kw::query>()?;
|
||||||
@ -178,7 +56,13 @@ impl Parse for Query {
|
|||||||
// Parse the query modifiers
|
// Parse the query modifiers
|
||||||
let content;
|
let content;
|
||||||
braced!(content in input);
|
braced!(content in input);
|
||||||
let modifiers = content.parse()?;
|
let modifiers = parse_query_modifiers(&content)?;
|
||||||
|
|
||||||
|
// If there are no doc-comments, give at least some idea of what
|
||||||
|
// it does by showing the query description.
|
||||||
|
if doc_comments.is_empty() {
|
||||||
|
doc_comments.push(doc_comment_from_desc(&modifiers.desc.1)?);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Query { doc_comments, modifiers, name, key, arg, result })
|
Ok(Query { doc_comments, modifiers, name, key, arg, result })
|
||||||
}
|
}
|
||||||
@ -205,7 +89,7 @@ struct QueryModifiers {
|
|||||||
storage: Option<Type>,
|
storage: Option<Type>,
|
||||||
|
|
||||||
/// Cache the query to disk if the `Block` returns true.
|
/// Cache the query to disk if the `Block` returns true.
|
||||||
cache: Option<(Option<IdentOrWild>, Block)>,
|
cache: Option<(Option<Pat>, Block)>,
|
||||||
|
|
||||||
/// Custom code to load the query from disk.
|
/// Custom code to load the query from disk.
|
||||||
load_cached: Option<(Ident, Ident, Block)>,
|
load_cached: Option<(Ident, Ident, Block)>,
|
||||||
@ -232,8 +116,7 @@ struct QueryModifiers {
|
|||||||
remap_env_constness: Option<Ident>,
|
remap_env_constness: Option<Ident>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process query modifiers into a struct, erroring on duplicates
|
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||||
fn process_modifiers(query: &mut Query) -> QueryModifiers {
|
|
||||||
let mut load_cached = None;
|
let mut load_cached = None;
|
||||||
let mut storage = None;
|
let mut storage = None;
|
||||||
let mut cache = None;
|
let mut cache = None;
|
||||||
@ -245,117 +128,84 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
|
|||||||
let mut eval_always = None;
|
let mut eval_always = None;
|
||||||
let mut separate_provide_extern = None;
|
let mut separate_provide_extern = None;
|
||||||
let mut remap_env_constness = None;
|
let mut remap_env_constness = None;
|
||||||
for modifier in query.modifiers.0.drain(..) {
|
|
||||||
match modifier {
|
while !input.is_empty() {
|
||||||
QueryModifier::LoadCached(tcx, id, block) => {
|
let modifier: Ident = input.parse()?;
|
||||||
if load_cached.is_some() {
|
|
||||||
panic!("duplicate modifier `load_cached` for query `{}`", query.name);
|
macro_rules! try_insert {
|
||||||
|
($name:ident = $expr:expr) => {
|
||||||
|
if $name.is_some() {
|
||||||
|
return Err(Error::new(modifier.span(), "duplicate modifier"));
|
||||||
}
|
}
|
||||||
load_cached = Some((tcx, id, block));
|
$name = Some($expr);
|
||||||
}
|
};
|
||||||
QueryModifier::Storage(ty) => {
|
}
|
||||||
if storage.is_some() {
|
|
||||||
panic!("duplicate modifier `storage` for query `{}`", query.name);
|
if modifier == "desc" {
|
||||||
}
|
// Parse a description modifier like:
|
||||||
storage = Some(ty);
|
// `desc { |tcx| "foo {}", tcx.item_path(key) }`
|
||||||
}
|
let attr_content;
|
||||||
QueryModifier::Cache(args, expr) => {
|
braced!(attr_content in input);
|
||||||
if cache.is_some() {
|
let tcx = if attr_content.peek(Token![|]) {
|
||||||
panic!("duplicate modifier `cache` for query `{}`", query.name);
|
attr_content.parse::<Token![|]>()?;
|
||||||
}
|
let tcx = attr_content.parse()?;
|
||||||
cache = Some((args, expr));
|
attr_content.parse::<Token![|]>()?;
|
||||||
}
|
Some(tcx)
|
||||||
QueryModifier::Desc(tcx, list) => {
|
} else {
|
||||||
if desc.is_some() {
|
None
|
||||||
panic!("duplicate modifier `desc` for query `{}`", query.name);
|
};
|
||||||
}
|
let list = attr_content.parse_terminated(Expr::parse)?;
|
||||||
// If there are no doc-comments, give at least some idea of what
|
try_insert!(desc = (tcx, list));
|
||||||
// it does by showing the query description.
|
} else if modifier == "cache_on_disk_if" {
|
||||||
if query.doc_comments.is_empty() {
|
// Parse a cache modifier like:
|
||||||
use ::syn::*;
|
// `cache(tcx) { |tcx| key.is_local() }`
|
||||||
let mut list = list.iter();
|
let args = if input.peek(token::Paren) {
|
||||||
let format_str: String = match list.next() {
|
let args;
|
||||||
Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
|
parenthesized!(args in input);
|
||||||
lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
|
let tcx = args.parse()?;
|
||||||
}
|
Some(tcx)
|
||||||
_ => panic!("Expected a string literal"),
|
} else {
|
||||||
};
|
None
|
||||||
let mut fmt_fragments = format_str.split("{}");
|
};
|
||||||
let mut doc_string = fmt_fragments.next().unwrap().to_string();
|
let block = input.parse()?;
|
||||||
list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
|
try_insert!(cache = (args, block));
|
||||||
|(tts, next_fmt_fragment)| {
|
} else if modifier == "load_cached" {
|
||||||
use ::core::fmt::Write;
|
// Parse a load_cached modifier like:
|
||||||
write!(
|
// `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }`
|
||||||
&mut doc_string,
|
let args;
|
||||||
" `{}` {}",
|
parenthesized!(args in input);
|
||||||
tts.to_string().replace(" . ", "."),
|
let tcx = args.parse()?;
|
||||||
next_fmt_fragment,
|
args.parse::<Token![,]>()?;
|
||||||
)
|
let id = args.parse()?;
|
||||||
.unwrap();
|
let block = input.parse()?;
|
||||||
},
|
try_insert!(load_cached = (tcx, id, block));
|
||||||
);
|
} else if modifier == "storage" {
|
||||||
let doc_string = format!(
|
let args;
|
||||||
"[query description - consider adding a doc-comment!] {}",
|
parenthesized!(args in input);
|
||||||
doc_string
|
let ty = args.parse()?;
|
||||||
);
|
try_insert!(storage = ty);
|
||||||
let comment = parse_quote! {
|
} else if modifier == "fatal_cycle" {
|
||||||
#[doc = #doc_string]
|
try_insert!(fatal_cycle = modifier);
|
||||||
};
|
} else if modifier == "cycle_delay_bug" {
|
||||||
query.doc_comments.push(comment);
|
try_insert!(cycle_delay_bug = modifier);
|
||||||
}
|
} else if modifier == "no_hash" {
|
||||||
desc = Some((tcx, list));
|
try_insert!(no_hash = modifier);
|
||||||
}
|
} else if modifier == "anon" {
|
||||||
QueryModifier::FatalCycle(ident) => {
|
try_insert!(anon = modifier);
|
||||||
if fatal_cycle.is_some() {
|
} else if modifier == "eval_always" {
|
||||||
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
|
try_insert!(eval_always = modifier);
|
||||||
}
|
} else if modifier == "separate_provide_extern" {
|
||||||
fatal_cycle = Some(ident);
|
try_insert!(separate_provide_extern = modifier);
|
||||||
}
|
} else if modifier == "remap_env_constness" {
|
||||||
QueryModifier::CycleDelayBug(ident) => {
|
try_insert!(remap_env_constness = modifier);
|
||||||
if cycle_delay_bug.is_some() {
|
} else {
|
||||||
panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name);
|
return Err(Error::new(modifier.span(), "unknown query modifier"));
|
||||||
}
|
|
||||||
cycle_delay_bug = Some(ident);
|
|
||||||
}
|
|
||||||
QueryModifier::NoHash(ident) => {
|
|
||||||
if no_hash.is_some() {
|
|
||||||
panic!("duplicate modifier `no_hash` for query `{}`", query.name);
|
|
||||||
}
|
|
||||||
no_hash = Some(ident);
|
|
||||||
}
|
|
||||||
QueryModifier::Anon(ident) => {
|
|
||||||
if anon.is_some() {
|
|
||||||
panic!("duplicate modifier `anon` for query `{}`", query.name);
|
|
||||||
}
|
|
||||||
anon = Some(ident);
|
|
||||||
}
|
|
||||||
QueryModifier::EvalAlways(ident) => {
|
|
||||||
if eval_always.is_some() {
|
|
||||||
panic!("duplicate modifier `eval_always` for query `{}`", query.name);
|
|
||||||
}
|
|
||||||
eval_always = Some(ident);
|
|
||||||
}
|
|
||||||
QueryModifier::SeparateProvideExtern(ident) => {
|
|
||||||
if separate_provide_extern.is_some() {
|
|
||||||
panic!(
|
|
||||||
"duplicate modifier `separate_provide_extern` for query `{}`",
|
|
||||||
query.name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
separate_provide_extern = Some(ident);
|
|
||||||
}
|
|
||||||
QueryModifier::RemapEnvConstness(ident) => {
|
|
||||||
if remap_env_constness.is_some() {
|
|
||||||
panic!("duplicate modifier `remap_env_constness` for query `{}`", query.name);
|
|
||||||
}
|
|
||||||
remap_env_constness = Some(ident)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let desc = desc.unwrap_or_else(|| {
|
let Some(desc) = desc else {
|
||||||
panic!("no description provided for query `{}`", query.name);
|
return Err(input.error("no description provided"));
|
||||||
});
|
};
|
||||||
QueryModifiers {
|
Ok(QueryModifiers {
|
||||||
load_cached,
|
load_cached,
|
||||||
storage,
|
storage,
|
||||||
cache,
|
cache,
|
||||||
@ -367,17 +217,41 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers {
|
|||||||
eval_always,
|
eval_always,
|
||||||
separate_provide_extern,
|
separate_provide_extern,
|
||||||
remap_env_constness,
|
remap_env_constness,
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attribute> {
|
||||||
|
use ::syn::*;
|
||||||
|
let mut iter = list.iter();
|
||||||
|
let format_str: String = match iter.next() {
|
||||||
|
Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
|
||||||
|
lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
|
||||||
|
}
|
||||||
|
_ => return Err(Error::new(list.span(), "Expected a string literal")),
|
||||||
|
};
|
||||||
|
let mut fmt_fragments = format_str.split("{}");
|
||||||
|
let mut doc_string = fmt_fragments.next().unwrap().to_string();
|
||||||
|
iter.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
|
||||||
|
|(tts, next_fmt_fragment)| {
|
||||||
|
use ::core::fmt::Write;
|
||||||
|
write!(
|
||||||
|
&mut doc_string,
|
||||||
|
" `{}` {}",
|
||||||
|
tts.to_string().replace(" . ", "."),
|
||||||
|
next_fmt_fragment,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let doc_string = format!("[query description - consider adding a doc-comment!] {}", doc_string);
|
||||||
|
Ok(parse_quote! { #[doc = #doc_string] })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the impl of QueryDescription for the query to `impls` if one is requested
|
/// Add the impl of QueryDescription for the query to `impls` if one is requested
|
||||||
fn add_query_description_impl(
|
fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
|
||||||
query: &Query,
|
|
||||||
modifiers: QueryModifiers,
|
|
||||||
impls: &mut proc_macro2::TokenStream,
|
|
||||||
) {
|
|
||||||
let name = &query.name;
|
let name = &query.name;
|
||||||
let key = &query.key.0;
|
let key = &query.key;
|
||||||
|
let modifiers = &query.modifiers;
|
||||||
|
|
||||||
// Find out if we should cache the query on disk
|
// Find out if we should cache the query on disk
|
||||||
let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
|
let cache = if let Some((args, expr)) = modifiers.cache.as_ref() {
|
||||||
@ -395,13 +269,7 @@ fn add_query_description_impl(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let tcx = args
|
let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ });
|
||||||
.as_ref()
|
|
||||||
.map(|t| {
|
|
||||||
let t = &t.0;
|
|
||||||
quote! { #t }
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| quote! { _ });
|
|
||||||
// expr is a `Block`, meaning that `{ #expr }` gets expanded
|
// expr is a `Block`, meaning that `{ #expr }` gets expanded
|
||||||
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
|
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
|
||||||
quote! {
|
quote! {
|
||||||
@ -427,7 +295,7 @@ fn add_query_description_impl(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (tcx, desc) = modifiers.desc;
|
let (tcx, desc) = &modifiers.desc;
|
||||||
let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t });
|
let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t });
|
||||||
|
|
||||||
let desc = quote! {
|
let desc = quote! {
|
||||||
@ -456,10 +324,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||||||
let mut dep_node_def_stream = quote! {};
|
let mut dep_node_def_stream = quote! {};
|
||||||
let mut cached_queries = quote! {};
|
let mut cached_queries = quote! {};
|
||||||
|
|
||||||
for mut query in queries.0 {
|
for query in queries.0 {
|
||||||
let modifiers = process_modifiers(&mut query);
|
let Query { name, arg, modifiers, .. } = &query;
|
||||||
let name = &query.name;
|
|
||||||
let arg = &query.arg;
|
|
||||||
let result_full = &query.result;
|
let result_full = &query.result;
|
||||||
let result = match query.result {
|
let result = match query.result {
|
||||||
ReturnType::Default => quote! { -> () },
|
ReturnType::Default => quote! { -> () },
|
||||||
@ -528,7 +394,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||||||
[#attribute_stream] #name(#arg),
|
[#attribute_stream] #name(#arg),
|
||||||
});
|
});
|
||||||
|
|
||||||
add_query_description_impl(&query, modifiers, &mut query_description_stream);
|
add_query_description_impl(&query, &mut query_description_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
@ -539,7 +405,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
|
|||||||
$($other)*
|
$($other)*
|
||||||
|
|
||||||
#query_stream
|
#query_stream
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
|
|||||||
}
|
}
|
||||||
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
|
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
|
||||||
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
|
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
|
||||||
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
|
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
|
||||||
_ => return Err(LitToConstError::TypeError),
|
_ => return Err(LitToConstError::TypeError),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ pub(crate) fn lit_to_const<'tcx>(
|
|||||||
}
|
}
|
||||||
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
|
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
|
||||||
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
|
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
|
||||||
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
|
(ast::LitKind::Err, _) => return Err(LitToConstError::Reported),
|
||||||
_ => return Err(LitToConstError::TypeError),
|
_ => return Err(LitToConstError::TypeError),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ where
|
|||||||
TerminatorKind::Unreachable
|
TerminatorKind::Unreachable
|
||||||
} else if is_unreachable(otherwise) {
|
} else if is_unreachable(otherwise) {
|
||||||
// If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise)
|
// If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise)
|
||||||
// unless otherwise is unrachable, in which case deleting a normal branch causes it to be merged with
|
// unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with
|
||||||
// the otherwise, keeping its unreachable.
|
// the otherwise, keeping its unreachable.
|
||||||
// This looses information about reachability causing worse codegen.
|
// This looses information about reachability causing worse codegen.
|
||||||
// For example (see src/test/codegen/match-optimizes-away.rs)
|
// For example (see src/test/codegen/match-optimizes-away.rs)
|
||||||
|
@ -1383,7 +1383,7 @@ impl<'a> Parser<'a> {
|
|||||||
match self.parse_str_lit() {
|
match self.parse_str_lit() {
|
||||||
Ok(str_lit) => Some(str_lit),
|
Ok(str_lit) => Some(str_lit),
|
||||||
Err(Some(lit)) => match lit.kind {
|
Err(Some(lit)) => match lit.kind {
|
||||||
ast::LitKind::Err(_) => None,
|
ast::LitKind::Err => None,
|
||||||
_ => {
|
_ => {
|
||||||
self.struct_span_err(lit.span, "non-string ABI literal")
|
self.struct_span_err(lit.span, "non-string ABI literal")
|
||||||
.span_suggestion(
|
.span_suggestion(
|
||||||
|
@ -264,9 +264,7 @@ impl<'a> Iterator for Parser<'a> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.is_literal {
|
if self.is_literal {
|
||||||
let start = self.to_span_index(self.cur_line_start);
|
let span = self.span(self.cur_line_start, self.input.len());
|
||||||
let end = self.to_span_index(self.input.len());
|
|
||||||
let span = start.to(end);
|
|
||||||
if self.line_spans.last() != Some(&span) {
|
if self.line_spans.last() != Some(&span) {
|
||||||
self.line_spans.push(span);
|
self.line_spans.push(span);
|
||||||
}
|
}
|
||||||
@ -384,6 +382,12 @@ impl<'a> Parser<'a> {
|
|||||||
InnerOffset(raw + pos + 1)
|
InnerOffset(raw + pos + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan {
|
||||||
|
let start = self.to_span_index(start_pos);
|
||||||
|
let end = self.to_span_index(end_pos);
|
||||||
|
start.to(end)
|
||||||
|
}
|
||||||
|
|
||||||
/// Forces consumption of the specified character. If the character is not
|
/// Forces consumption of the specified character. If the character is not
|
||||||
/// found, an error is emitted.
|
/// found, an error is emitted.
|
||||||
fn must_consume(&mut self, c: char) -> Option<usize> {
|
fn must_consume(&mut self, c: char) -> Option<usize> {
|
||||||
@ -472,9 +476,7 @@ impl<'a> Parser<'a> {
|
|||||||
return &self.input[start..pos];
|
return &self.input[start..pos];
|
||||||
}
|
}
|
||||||
'\n' if self.is_literal => {
|
'\n' if self.is_literal => {
|
||||||
let start = self.to_span_index(self.cur_line_start);
|
self.line_spans.push(self.span(self.cur_line_start, pos));
|
||||||
let end = self.to_span_index(pos);
|
|
||||||
self.line_spans.push(start.to(end));
|
|
||||||
self.cur_line_start = pos + 1;
|
self.cur_line_start = pos + 1;
|
||||||
self.cur.next();
|
self.cur.next();
|
||||||
}
|
}
|
||||||
@ -537,6 +539,10 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn current_pos(&mut self) -> usize {
|
||||||
|
if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a format specifier at the current position, returning all of the
|
/// Parses a format specifier at the current position, returning all of the
|
||||||
/// relevant information in the `FormatSpec` struct.
|
/// relevant information in the `FormatSpec` struct.
|
||||||
fn format(&mut self) -> FormatSpec<'a> {
|
fn format(&mut self) -> FormatSpec<'a> {
|
||||||
@ -590,39 +596,37 @@ impl<'a> Parser<'a> {
|
|||||||
// no '0' flag and '0$' as the width instead.
|
// no '0' flag and '0$' as the width instead.
|
||||||
if let Some(end) = self.consume_pos('$') {
|
if let Some(end) = self.consume_pos('$') {
|
||||||
spec.width = CountIsParam(0);
|
spec.width = CountIsParam(0);
|
||||||
|
spec.width_span = Some(self.span(end - 1, end + 1));
|
||||||
if let Some((pos, _)) = self.cur.peek().cloned() {
|
|
||||||
spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos)));
|
|
||||||
}
|
|
||||||
havewidth = true;
|
havewidth = true;
|
||||||
spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1)));
|
|
||||||
} else {
|
} else {
|
||||||
spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
|
spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !havewidth {
|
if !havewidth {
|
||||||
let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 };
|
let start = self.current_pos();
|
||||||
let (w, sp) = self.count(width_span_start);
|
spec.width = self.count(start);
|
||||||
spec.width = w;
|
if spec.width != CountImplied {
|
||||||
spec.width_span = sp;
|
let end = self.current_pos();
|
||||||
|
spec.width_span = Some(self.span(start, end));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(start) = self.consume_pos('.') {
|
if let Some(start) = self.consume_pos('.') {
|
||||||
if let Some(end) = self.consume_pos('*') {
|
if self.consume('*') {
|
||||||
// Resolve `CountIsNextParam`.
|
// Resolve `CountIsNextParam`.
|
||||||
// We can do this immediately as `position` is resolved later.
|
// We can do this immediately as `position` is resolved later.
|
||||||
let i = self.curarg;
|
let i = self.curarg;
|
||||||
self.curarg += 1;
|
self.curarg += 1;
|
||||||
spec.precision = CountIsParam(i);
|
spec.precision = CountIsParam(i);
|
||||||
spec.precision_span =
|
|
||||||
Some(self.to_span_index(start).to(self.to_span_index(end + 1)));
|
|
||||||
} else {
|
} else {
|
||||||
let (p, sp) = self.count(start);
|
spec.precision = self.count(start + 1);
|
||||||
spec.precision = p;
|
|
||||||
spec.precision_span = sp;
|
|
||||||
}
|
}
|
||||||
|
let end = self.current_pos();
|
||||||
|
spec.precision_span = Some(self.span(start, end));
|
||||||
}
|
}
|
||||||
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
|
|
||||||
|
let ty_span_start = self.current_pos();
|
||||||
// Optional radix followed by the actual format specifier
|
// Optional radix followed by the actual format specifier
|
||||||
if self.consume('x') {
|
if self.consume('x') {
|
||||||
if self.consume('?') {
|
if self.consume('?') {
|
||||||
@ -642,11 +646,9 @@ impl<'a> Parser<'a> {
|
|||||||
spec.ty = "?";
|
spec.ty = "?";
|
||||||
} else {
|
} else {
|
||||||
spec.ty = self.word();
|
spec.ty = self.word();
|
||||||
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
|
|
||||||
if !spec.ty.is_empty() {
|
if !spec.ty.is_empty() {
|
||||||
spec.ty_span = ty_span_start
|
let ty_span_end = self.current_pos();
|
||||||
.and_then(|s| ty_span_end.map(|e| (s, e)))
|
spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
|
||||||
.map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spec
|
spec
|
||||||
@ -670,13 +672,11 @@ impl<'a> Parser<'a> {
|
|||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty_span_start = self.cur.peek().map(|(pos, _)| *pos);
|
let ty_span_start = self.current_pos();
|
||||||
spec.ty = self.word();
|
spec.ty = self.word();
|
||||||
let ty_span_end = self.cur.peek().map(|(pos, _)| *pos);
|
|
||||||
if !spec.ty.is_empty() {
|
if !spec.ty.is_empty() {
|
||||||
spec.ty_span = ty_span_start
|
let ty_span_end = self.current_pos();
|
||||||
.and_then(|s| ty_span_end.map(|e| (s, e)))
|
spec.ty_span = Some(self.span(ty_span_start, ty_span_end));
|
||||||
.map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spec
|
spec
|
||||||
@ -685,26 +685,21 @@ impl<'a> Parser<'a> {
|
|||||||
/// Parses a `Count` parameter at the current position. This does not check
|
/// Parses a `Count` parameter at the current position. This does not check
|
||||||
/// for 'CountIsNextParam' because that is only used in precision, not
|
/// for 'CountIsNextParam' because that is only used in precision, not
|
||||||
/// width.
|
/// width.
|
||||||
fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
|
fn count(&mut self, start: usize) -> Count<'a> {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
if let Some(end) = self.consume_pos('$') {
|
if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
|
||||||
let span = self.to_span_index(start).to(self.to_span_index(end + 1));
|
|
||||||
(CountIsParam(i), Some(span))
|
|
||||||
} else {
|
|
||||||
(CountIs(i), None)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let tmp = self.cur.clone();
|
let tmp = self.cur.clone();
|
||||||
let word = self.word();
|
let word = self.word();
|
||||||
if word.is_empty() {
|
if word.is_empty() {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
(CountImplied, None)
|
CountImplied
|
||||||
} else if let Some(end) = self.consume_pos('$') {
|
} else if let Some(end) = self.consume_pos('$') {
|
||||||
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
|
let name_span = self.span(start, end);
|
||||||
(CountIsName(word, span), None)
|
CountIsName(word, name_span)
|
||||||
} else {
|
} else {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
(CountImplied, None)
|
CountImplied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -737,7 +732,7 @@ impl<'a> Parser<'a> {
|
|||||||
"invalid argument name `_`",
|
"invalid argument name `_`",
|
||||||
"invalid argument name",
|
"invalid argument name",
|
||||||
"argument name cannot be a single underscore",
|
"argument name cannot be a single underscore",
|
||||||
self.to_span_index(start).to(self.to_span_index(end)),
|
self.span(start, end),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
word
|
word
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
fn same(fmt: &'static str, p: &[Piece<'static>]) {
|
fn same(fmt: &'static str, p: &[Piece<'static>]) {
|
||||||
let parser = Parser::new(fmt, None, None, false, ParseMode::Format);
|
let parser = Parser::new(fmt, None, None, false, ParseMode::Format);
|
||||||
assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p);
|
assert_eq!(parser.collect::<Vec<Piece<'static>>>(), p);
|
||||||
@ -190,9 +191,9 @@ fn format_counts() {
|
|||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountImplied,
|
precision: CountImplied,
|
||||||
width: CountIs(10),
|
|
||||||
precision_span: None,
|
precision_span: None,
|
||||||
width_span: None,
|
width: CountIs(10),
|
||||||
|
width_span: Some(InnerSpan { start: 3, end: 5 }),
|
||||||
ty: "x",
|
ty: "x",
|
||||||
ty_span: None,
|
ty_span: None,
|
||||||
},
|
},
|
||||||
@ -208,9 +209,9 @@ fn format_counts() {
|
|||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIs(10),
|
precision: CountIs(10),
|
||||||
|
precision_span: Some(InnerSpan { start: 6, end: 9 }),
|
||||||
width: CountIsParam(10),
|
width: CountIsParam(10),
|
||||||
precision_span: None,
|
width_span: Some(InnerSpan { start: 3, end: 6 }),
|
||||||
width_span: Some(InnerSpan::new(3, 6)),
|
|
||||||
ty: "x",
|
ty: "x",
|
||||||
ty_span: None,
|
ty_span: None,
|
||||||
},
|
},
|
||||||
@ -226,9 +227,9 @@ fn format_counts() {
|
|||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIs(10),
|
precision: CountIs(10),
|
||||||
|
precision_span: Some(InnerSpan { start: 6, end: 9 }),
|
||||||
width: CountIsParam(0),
|
width: CountIsParam(0),
|
||||||
precision_span: None,
|
width_span: Some(InnerSpan { start: 4, end: 6 }),
|
||||||
width_span: Some(InnerSpan::new(4, 6)),
|
|
||||||
ty: "x",
|
ty: "x",
|
||||||
ty_span: None,
|
ty_span: None,
|
||||||
},
|
},
|
||||||
@ -244,8 +245,8 @@ fn format_counts() {
|
|||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIsParam(0),
|
precision: CountIsParam(0),
|
||||||
|
precision_span: Some(InnerSpan { start: 3, end: 5 }),
|
||||||
width: CountImplied,
|
width: CountImplied,
|
||||||
precision_span: Some(InnerSpan::new(3, 5)),
|
|
||||||
width_span: None,
|
width_span: None,
|
||||||
ty: "x",
|
ty: "x",
|
||||||
ty_span: None,
|
ty_span: None,
|
||||||
@ -279,15 +280,33 @@ fn format_counts() {
|
|||||||
fill: None,
|
fill: None,
|
||||||
align: AlignUnknown,
|
align: AlignUnknown,
|
||||||
flags: 0,
|
flags: 0,
|
||||||
precision: CountIsName("b", InnerSpan::new(6, 7)),
|
precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
|
||||||
width: CountIsName("a", InnerSpan::new(4, 4)),
|
precision_span: Some(InnerSpan { start: 5, end: 8 }),
|
||||||
precision_span: None,
|
width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
|
||||||
width_span: None,
|
width_span: Some(InnerSpan { start: 3, end: 5 }),
|
||||||
ty: "?",
|
ty: "?",
|
||||||
ty_span: None,
|
ty_span: None,
|
||||||
},
|
},
|
||||||
})],
|
})],
|
||||||
);
|
);
|
||||||
|
same(
|
||||||
|
"{:.4}",
|
||||||
|
&[NextArgument(Argument {
|
||||||
|
position: ArgumentImplicitlyIs(0),
|
||||||
|
position_span: InnerSpan { start: 2, end: 2 },
|
||||||
|
format: FormatSpec {
|
||||||
|
fill: None,
|
||||||
|
align: AlignUnknown,
|
||||||
|
flags: 0,
|
||||||
|
precision: CountIs(4),
|
||||||
|
precision_span: Some(InnerSpan { start: 3, end: 5 }),
|
||||||
|
width: CountImplied,
|
||||||
|
width_span: None,
|
||||||
|
ty: "",
|
||||||
|
ty_span: None,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_flags() {
|
fn format_flags() {
|
||||||
|
@ -11,6 +11,7 @@ doctest = false
|
|||||||
libloading = "0.7.1"
|
libloading = "0.7.1"
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_lint = { path = "../rustc_lint" }
|
rustc_lint = { path = "../rustc_lint" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_metadata = { path = "../rustc_metadata" }
|
rustc_metadata = { path = "../rustc_metadata" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_session = { path = "../rustc_session" }
|
rustc_session = { path = "../rustc_session" }
|
||||||
|
20
compiler/rustc_plugin_impl/src/errors.rs
Normal file
20
compiler/rustc_plugin_impl/src/errors.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! Errors emitted by plugin_impl
|
||||||
|
|
||||||
|
use rustc_macros::SessionDiagnostic;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(plugin_impl::load_plugin_error)]
|
||||||
|
pub struct LoadPluginError {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub msg: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")]
|
||||||
|
pub struct MalformedPluginAttribute {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
|
||||||
use rustc_lint::LintStore;
|
use rustc_lint::LintStore;
|
||||||
|
|
||||||
|
mod errors;
|
||||||
pub mod load;
|
pub mod load;
|
||||||
|
|
||||||
/// Structure used to register plugins.
|
/// Structure used to register plugins.
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
//! Used by `rustc` when loading a plugin.
|
//! Used by `rustc` when loading a plugin.
|
||||||
|
|
||||||
|
use crate::errors::{LoadPluginError, MalformedPluginAttribute};
|
||||||
use crate::Registry;
|
use crate::Registry;
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use rustc_ast::Crate;
|
use rustc_ast::Crate;
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_metadata::locator;
|
use rustc_metadata::locator;
|
||||||
use rustc_session::cstore::MetadataLoader;
|
use rustc_session::cstore::MetadataLoader;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::{sym, Ident};
|
use rustc_span::symbol::{sym, Ident};
|
||||||
use rustc_span::Span;
|
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -18,12 +16,6 @@ use std::path::PathBuf;
|
|||||||
/// Pointer to a registrar function.
|
/// Pointer to a registrar function.
|
||||||
type PluginRegistrarFn = fn(&mut Registry<'_>);
|
type PluginRegistrarFn = fn(&mut Registry<'_>);
|
||||||
|
|
||||||
fn call_malformed_plugin_attribute(sess: &Session, span: Span) {
|
|
||||||
struct_span_err!(sess, span, E0498, "malformed `plugin` attribute")
|
|
||||||
.span_label(span, "malformed attribute")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read plugin metadata and dynamically load registrar functions.
|
/// Read plugin metadata and dynamically load registrar functions.
|
||||||
pub fn load_plugins(
|
pub fn load_plugins(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
@ -42,7 +34,9 @@ pub fn load_plugins(
|
|||||||
Some(ident) if plugin.is_word() => {
|
Some(ident) if plugin.is_word() => {
|
||||||
load_plugin(&mut plugins, sess, metadata_loader, ident)
|
load_plugin(&mut plugins, sess, metadata_loader, ident)
|
||||||
}
|
}
|
||||||
_ => call_malformed_plugin_attribute(sess, plugin.span()),
|
_ => {
|
||||||
|
sess.emit_err(MalformedPluginAttribute { span: plugin.span() });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +54,7 @@ fn load_plugin(
|
|||||||
let fun = dylink_registrar(lib).unwrap_or_else(|err| {
|
let fun = dylink_registrar(lib).unwrap_or_else(|err| {
|
||||||
// This is fatal: there are almost certainly macros we need inside this crate, so
|
// This is fatal: there are almost certainly macros we need inside this crate, so
|
||||||
// continuing would spew "macro undefined" errors.
|
// continuing would spew "macro undefined" errors.
|
||||||
sess.span_fatal(ident.span, &err.to_string());
|
sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() });
|
||||||
});
|
});
|
||||||
plugins.push(fun);
|
plugins.push(fun);
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,7 @@ impl<'a> Resolver<'a> {
|
|||||||
err.span_label(span, "use of generic parameter from outer function");
|
err.span_label(span, "use of generic parameter from outer function");
|
||||||
|
|
||||||
let sm = self.session.source_map();
|
let sm = self.session.source_map();
|
||||||
match outer_res {
|
let def_id = match outer_res {
|
||||||
Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
|
Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
|
||||||
if let Some(impl_span) =
|
if let Some(impl_span) =
|
||||||
maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
|
maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
|
||||||
@ -536,11 +536,13 @@ impl<'a> Resolver<'a> {
|
|||||||
if let Some(span) = self.opt_span(def_id) {
|
if let Some(span) = self.opt_span(def_id) {
|
||||||
err.span_label(span, "type parameter from outer function");
|
err.span_label(span, "type parameter from outer function");
|
||||||
}
|
}
|
||||||
|
def_id
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::ConstParam, def_id) => {
|
Res::Def(DefKind::ConstParam, def_id) => {
|
||||||
if let Some(span) = self.opt_span(def_id) {
|
if let Some(span) = self.opt_span(def_id) {
|
||||||
err.span_label(span, "const parameter from outer function");
|
err.span_label(span, "const parameter from outer function");
|
||||||
}
|
}
|
||||||
|
def_id
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bug!(
|
bug!(
|
||||||
@ -548,28 +550,23 @@ impl<'a> Resolver<'a> {
|
|||||||
DefKind::TyParam or DefKind::ConstParam"
|
DefKind::TyParam or DefKind::ConstParam"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if has_generic_params == HasGenericParams::Yes {
|
if let HasGenericParams::Yes(span) = has_generic_params {
|
||||||
// Try to retrieve the span of the function signature and generate a new
|
// Try to retrieve the span of the function signature and generate a new
|
||||||
// message with a local type or const parameter.
|
// message with a local type or const parameter.
|
||||||
let sugg_msg = "try using a local generic parameter instead";
|
let sugg_msg = "try using a local generic parameter instead";
|
||||||
if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) {
|
let name = self.opt_name(def_id).unwrap_or(sym::T);
|
||||||
// Suggest the modification to the user
|
let (span, snippet) = if span.is_empty() {
|
||||||
err.span_suggestion(
|
let snippet = format!("<{}>", name);
|
||||||
sugg_span,
|
(span, snippet)
|
||||||
sugg_msg,
|
|
||||||
snippet,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
} else if let Some(sp) = sm.generate_fn_name_span(span) {
|
|
||||||
err.span_label(
|
|
||||||
sp,
|
|
||||||
"try adding a local generic parameter in this method instead",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
err.help("try using a local generic parameter instead");
|
let span = sm.span_through_char(span, '<').shrink_to_hi();
|
||||||
}
|
let snippet = format!("{}, ", name);
|
||||||
|
(span, snippet)
|
||||||
|
};
|
||||||
|
// Suggest the modification to the user
|
||||||
|
err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
|
@ -13,7 +13,9 @@ use rustc_span::{Span, DUMMY_SP};
|
|||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind};
|
use crate::late::{
|
||||||
|
ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind,
|
||||||
|
};
|
||||||
use crate::macros::{sub_namespace_match, MacroRulesScope};
|
use crate::macros::{sub_namespace_match, MacroRulesScope};
|
||||||
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
|
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
|
||||||
use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
|
use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
|
||||||
@ -1103,7 +1105,7 @@ impl<'a> Resolver<'a> {
|
|||||||
| ForwardGenericParamBanRibKind => {
|
| ForwardGenericParamBanRibKind => {
|
||||||
// Nothing to do. Continue.
|
// Nothing to do. Continue.
|
||||||
}
|
}
|
||||||
ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
|
ItemRibKind(_) | AssocItemRibKind => {
|
||||||
// This was an attempt to access an upvar inside a
|
// This was an attempt to access an upvar inside a
|
||||||
// named function item. This is not allowed, so we
|
// named function item. This is not allowed, so we
|
||||||
// report an error.
|
// report an error.
|
||||||
@ -1168,10 +1170,10 @@ impl<'a> Resolver<'a> {
|
|||||||
let has_generic_params: HasGenericParams = match rib.kind {
|
let has_generic_params: HasGenericParams = match rib.kind {
|
||||||
NormalRibKind
|
NormalRibKind
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| AssocItemRibKind
|
|
||||||
| ModuleRibKind(..)
|
| ModuleRibKind(..)
|
||||||
| MacroDefinition(..)
|
| MacroDefinition(..)
|
||||||
| InlineAsmSymRibKind
|
| InlineAsmSymRibKind
|
||||||
|
| AssocItemRibKind
|
||||||
| ForwardGenericParamBanRibKind => {
|
| ForwardGenericParamBanRibKind => {
|
||||||
// Nothing to do. Continue.
|
// Nothing to do. Continue.
|
||||||
continue;
|
continue;
|
||||||
@ -1180,7 +1182,9 @@ impl<'a> Resolver<'a> {
|
|||||||
ConstantItemRibKind(trivial, _) => {
|
ConstantItemRibKind(trivial, _) => {
|
||||||
let features = self.session.features_untracked();
|
let features = self.session.features_untracked();
|
||||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
||||||
if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
|
if !(trivial == ConstantHasGenerics::Yes
|
||||||
|
|| features.generic_const_exprs)
|
||||||
|
{
|
||||||
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
|
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
|
||||||
// we can't easily tell if it's generic at this stage, so we instead remember
|
// we can't easily tell if it's generic at this stage, so we instead remember
|
||||||
// this and then enforce the self type to be concrete later on.
|
// this and then enforce the self type to be concrete later on.
|
||||||
@ -1207,7 +1211,6 @@ impl<'a> Resolver<'a> {
|
|||||||
|
|
||||||
// This was an attempt to use a type parameter outside its scope.
|
// This was an attempt to use a type parameter outside its scope.
|
||||||
ItemRibKind(has_generic_params) => has_generic_params,
|
ItemRibKind(has_generic_params) => has_generic_params,
|
||||||
FnItemRibKind => HasGenericParams::Yes,
|
|
||||||
ConstParamTyRibKind => {
|
ConstParamTyRibKind => {
|
||||||
if let Some(span) = finalize {
|
if let Some(span) = finalize {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
@ -1232,28 +1235,22 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Res::Def(DefKind::ConstParam, _) => {
|
Res::Def(DefKind::ConstParam, _) => {
|
||||||
let mut ribs = ribs.iter().peekable();
|
|
||||||
if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() {
|
|
||||||
// When declaring const parameters inside function signatures, the first rib
|
|
||||||
// is always a `FnItemRibKind`. In this case, we can skip it, to avoid it
|
|
||||||
// (spuriously) conflicting with the const param.
|
|
||||||
ribs.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
for rib in ribs {
|
for rib in ribs {
|
||||||
let has_generic_params = match rib.kind {
|
let has_generic_params = match rib.kind {
|
||||||
NormalRibKind
|
NormalRibKind
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| AssocItemRibKind
|
|
||||||
| ModuleRibKind(..)
|
| ModuleRibKind(..)
|
||||||
| MacroDefinition(..)
|
| MacroDefinition(..)
|
||||||
| InlineAsmSymRibKind
|
| InlineAsmSymRibKind
|
||||||
|
| AssocItemRibKind
|
||||||
| ForwardGenericParamBanRibKind => continue,
|
| ForwardGenericParamBanRibKind => continue,
|
||||||
|
|
||||||
ConstantItemRibKind(trivial, _) => {
|
ConstantItemRibKind(trivial, _) => {
|
||||||
let features = self.session.features_untracked();
|
let features = self.session.features_untracked();
|
||||||
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
|
||||||
if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) {
|
if !(trivial == ConstantHasGenerics::Yes
|
||||||
|
|| features.generic_const_exprs)
|
||||||
|
{
|
||||||
if let Some(span) = finalize {
|
if let Some(span) = finalize {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
span,
|
span,
|
||||||
@ -1272,7 +1269,6 @@ impl<'a> Resolver<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemRibKind(has_generic_params) => has_generic_params,
|
ItemRibKind(has_generic_params) => has_generic_params,
|
||||||
FnItemRibKind => HasGenericParams::Yes,
|
|
||||||
ConstParamTyRibKind => {
|
ConstParamTyRibKind => {
|
||||||
if let Some(span) = finalize {
|
if let Some(span) = finalize {
|
||||||
self.report_error(
|
self.report_error(
|
||||||
|
@ -91,13 +91,20 @@ enum PatBoundCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Does this the item (from the item rib scope) allow generic parameters?
|
/// Does this the item (from the item rib scope) allow generic parameters?
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) enum HasGenericParams {
|
pub(crate) enum HasGenericParams {
|
||||||
|
Yes(Span),
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// May this constant have generics?
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub(crate) enum ConstantHasGenerics {
|
||||||
Yes,
|
Yes,
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasGenericParams {
|
impl ConstantHasGenerics {
|
||||||
fn force_yes_if(self, b: bool) -> Self {
|
fn force_yes_if(self, b: bool) -> Self {
|
||||||
if b { Self::Yes } else { self }
|
if b { Self::Yes } else { self }
|
||||||
}
|
}
|
||||||
@ -125,10 +132,6 @@ pub(crate) enum RibKind<'a> {
|
|||||||
/// We passed through a closure. Disallow labels.
|
/// We passed through a closure. Disallow labels.
|
||||||
ClosureOrAsyncRibKind,
|
ClosureOrAsyncRibKind,
|
||||||
|
|
||||||
/// We passed through a function definition. Disallow upvars.
|
|
||||||
/// Permit only those const parameters that are specified in the function's generics.
|
|
||||||
FnItemRibKind,
|
|
||||||
|
|
||||||
/// We passed through an item scope. Disallow upvars.
|
/// We passed through an item scope. Disallow upvars.
|
||||||
ItemRibKind(HasGenericParams),
|
ItemRibKind(HasGenericParams),
|
||||||
|
|
||||||
@ -136,7 +139,7 @@ pub(crate) enum RibKind<'a> {
|
|||||||
///
|
///
|
||||||
/// The item may reference generic parameters in trivial constant expressions.
|
/// The item may reference generic parameters in trivial constant expressions.
|
||||||
/// All other constants aren't allowed to use generic params at all.
|
/// All other constants aren't allowed to use generic params at all.
|
||||||
ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>),
|
ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>),
|
||||||
|
|
||||||
/// We passed through a module.
|
/// We passed through a module.
|
||||||
ModuleRibKind(Module<'a>),
|
ModuleRibKind(Module<'a>),
|
||||||
@ -165,7 +168,6 @@ impl RibKind<'_> {
|
|||||||
match self {
|
match self {
|
||||||
NormalRibKind
|
NormalRibKind
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| FnItemRibKind
|
|
||||||
| ConstantItemRibKind(..)
|
| ConstantItemRibKind(..)
|
||||||
| ModuleRibKind(_)
|
| ModuleRibKind(_)
|
||||||
| MacroDefinition(_)
|
| MacroDefinition(_)
|
||||||
@ -182,7 +184,6 @@ impl RibKind<'_> {
|
|||||||
|
|
||||||
AssocItemRibKind
|
AssocItemRibKind
|
||||||
| ClosureOrAsyncRibKind
|
| ClosureOrAsyncRibKind
|
||||||
| FnItemRibKind
|
|
||||||
| ItemRibKind(..)
|
| ItemRibKind(..)
|
||||||
| ConstantItemRibKind(..)
|
| ConstantItemRibKind(..)
|
||||||
| ModuleRibKind(..)
|
| ModuleRibKind(..)
|
||||||
@ -751,7 +752,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||||||
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
||||||
this.with_generic_param_rib(
|
this.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: foreign_item.id,
|
binder: foreign_item.id,
|
||||||
kind: LifetimeBinderKind::Item,
|
kind: LifetimeBinderKind::Item,
|
||||||
@ -765,7 +766,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||||||
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
self.with_lifetime_rib(LifetimeRibKind::Item, |this| {
|
||||||
this.with_generic_param_rib(
|
this.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: foreign_item.id,
|
binder: foreign_item.id,
|
||||||
kind: LifetimeBinderKind::Function,
|
kind: LifetimeBinderKind::Function,
|
||||||
@ -786,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
|
fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) {
|
||||||
let rib_kind = match fn_kind {
|
let previous_value = self.diagnostic_metadata.current_function;
|
||||||
|
match fn_kind {
|
||||||
// Bail if the function is foreign, and thus cannot validly have
|
// Bail if the function is foreign, and thus cannot validly have
|
||||||
// a body, or if there's no body for some other reason.
|
// a body, or if there's no body for some other reason.
|
||||||
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
|
FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
|
||||||
@ -809,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
|
FnKind::Fn(..) => {
|
||||||
FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
|
self.diagnostic_metadata.current_function = Some((fn_kind, sp));
|
||||||
FnKind::Closure(..) => ClosureOrAsyncRibKind,
|
}
|
||||||
|
// Do not update `current_function` for closures: it suggests `self` parameters.
|
||||||
|
FnKind::Closure(..) => {}
|
||||||
};
|
};
|
||||||
let previous_value = self.diagnostic_metadata.current_function;
|
|
||||||
if matches!(fn_kind, FnKind::Fn(..)) {
|
|
||||||
self.diagnostic_metadata.current_function = Some((fn_kind, sp));
|
|
||||||
}
|
|
||||||
debug!("(resolving function) entering function");
|
debug!("(resolving function) entering function");
|
||||||
|
|
||||||
// Create a value rib for the function.
|
// Create a value rib for the function.
|
||||||
self.with_rib(ValueNS, rib_kind, |this| {
|
self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| {
|
||||||
// Create a label rib for the function.
|
// Create a label rib for the function.
|
||||||
this.with_label_rib(FnItemRibKind, |this| {
|
this.with_label_rib(ClosureOrAsyncRibKind, |this| {
|
||||||
match fn_kind {
|
match fn_kind {
|
||||||
FnKind::Fn(_, _, sig, _, generics, body) => {
|
FnKind::Fn(_, _, sig, _, generics, body) => {
|
||||||
this.visit_generics(generics);
|
this.visit_generics(generics);
|
||||||
@ -995,7 +995,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
|||||||
// non-trivial constants this is doesn't matter.
|
// non-trivial constants this is doesn't matter.
|
||||||
self.with_constant_rib(
|
self.with_constant_rib(
|
||||||
IsRepeatExpr::No,
|
IsRepeatExpr::No,
|
||||||
HasGenericParams::Yes,
|
ConstantHasGenerics::Yes,
|
||||||
None,
|
None,
|
||||||
|this| {
|
|this| {
|
||||||
this.smart_resolve_path(
|
this.smart_resolve_path(
|
||||||
@ -2071,7 +2071,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
self.with_current_self_item(item, |this| {
|
self.with_current_self_item(item, |this| {
|
||||||
this.with_generic_param_rib(
|
this.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: item.id,
|
binder: item.id,
|
||||||
kind: LifetimeBinderKind::Item,
|
kind: LifetimeBinderKind::Item,
|
||||||
@ -2141,7 +2141,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
|
ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: item.id,
|
binder: item.id,
|
||||||
kind: LifetimeBinderKind::Item,
|
kind: LifetimeBinderKind::Item,
|
||||||
@ -2154,7 +2154,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
ItemKind::Fn(box Fn { ref generics, .. }) => {
|
ItemKind::Fn(box Fn { ref generics, .. }) => {
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: item.id,
|
binder: item.id,
|
||||||
kind: LifetimeBinderKind::Function,
|
kind: LifetimeBinderKind::Function,
|
||||||
@ -2186,7 +2186,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
// Create a new rib for the trait-wide type parameters.
|
// Create a new rib for the trait-wide type parameters.
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: item.id,
|
binder: item.id,
|
||||||
kind: LifetimeBinderKind::Item,
|
kind: LifetimeBinderKind::Item,
|
||||||
@ -2210,7 +2210,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
// Create a new rib for the trait-wide type parameters.
|
// Create a new rib for the trait-wide type parameters.
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
binder: item.id,
|
binder: item.id,
|
||||||
kind: LifetimeBinderKind::Item,
|
kind: LifetimeBinderKind::Item,
|
||||||
@ -2251,7 +2251,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
// so it doesn't matter whether this is a trivial constant.
|
// so it doesn't matter whether this is a trivial constant.
|
||||||
this.with_constant_rib(
|
this.with_constant_rib(
|
||||||
IsRepeatExpr::No,
|
IsRepeatExpr::No,
|
||||||
HasGenericParams::Yes,
|
ConstantHasGenerics::Yes,
|
||||||
Some((item.ident, constant_item_kind)),
|
Some((item.ident, constant_item_kind)),
|
||||||
|this| this.visit_expr(expr),
|
|this| this.visit_expr(expr),
|
||||||
);
|
);
|
||||||
@ -2450,7 +2450,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
fn with_constant_rib(
|
fn with_constant_rib(
|
||||||
&mut self,
|
&mut self,
|
||||||
is_repeat: IsRepeatExpr,
|
is_repeat: IsRepeatExpr,
|
||||||
may_use_generics: HasGenericParams,
|
may_use_generics: ConstantHasGenerics,
|
||||||
item: Option<(Ident, ConstantItemKind)>,
|
item: Option<(Ident, ConstantItemKind)>,
|
||||||
f: impl FnOnce(&mut Self),
|
f: impl FnOnce(&mut Self),
|
||||||
) {
|
) {
|
||||||
@ -2517,7 +2517,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
|this| {
|
|this| {
|
||||||
this.with_constant_rib(
|
this.with_constant_rib(
|
||||||
IsRepeatExpr::No,
|
IsRepeatExpr::No,
|
||||||
HasGenericParams::Yes,
|
ConstantHasGenerics::Yes,
|
||||||
None,
|
None,
|
||||||
|this| this.visit_expr(expr),
|
|this| this.visit_expr(expr),
|
||||||
)
|
)
|
||||||
@ -2598,7 +2598,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
// If applicable, create a rib for the type parameters.
|
// If applicable, create a rib for the type parameters.
|
||||||
self.with_generic_param_rib(
|
self.with_generic_param_rib(
|
||||||
&generics.params,
|
&generics.params,
|
||||||
ItemRibKind(HasGenericParams::Yes),
|
ItemRibKind(HasGenericParams::Yes(generics.span)),
|
||||||
LifetimeRibKind::Generics {
|
LifetimeRibKind::Generics {
|
||||||
span: generics.span,
|
span: generics.span,
|
||||||
binder: item_id,
|
binder: item_id,
|
||||||
@ -2689,7 +2689,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||||
this.with_constant_rib(
|
this.with_constant_rib(
|
||||||
IsRepeatExpr::No,
|
IsRepeatExpr::No,
|
||||||
HasGenericParams::Yes,
|
ConstantHasGenerics::Yes,
|
||||||
None,
|
None,
|
||||||
|this| this.visit_expr(expr),
|
|this| this.visit_expr(expr),
|
||||||
)
|
)
|
||||||
@ -3696,9 +3696,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
self.with_constant_rib(
|
self.with_constant_rib(
|
||||||
is_repeat,
|
is_repeat,
|
||||||
if constant.value.is_potential_trivial_const_param() {
|
if constant.value.is_potential_trivial_const_param() {
|
||||||
HasGenericParams::Yes
|
ConstantHasGenerics::Yes
|
||||||
} else {
|
} else {
|
||||||
HasGenericParams::No
|
ConstantHasGenerics::No
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|this| visit::walk_anon_const(this, constant),
|
|this| visit::walk_anon_const(this, constant),
|
||||||
@ -3707,8 +3707,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
|
|
||||||
fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
|
fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
|
||||||
debug!("resolve_anon_const {constant:?}");
|
debug!("resolve_anon_const {constant:?}");
|
||||||
self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| {
|
self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| {
|
||||||
visit::walk_anon_const(this, constant);
|
visit::walk_anon_const(this, constant)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3814,9 +3814,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
|||||||
self.with_constant_rib(
|
self.with_constant_rib(
|
||||||
IsRepeatExpr::No,
|
IsRepeatExpr::No,
|
||||||
if argument.is_potential_trivial_const_param() {
|
if argument.is_potential_trivial_const_param() {
|
||||||
HasGenericParams::Yes
|
ConstantHasGenerics::Yes
|
||||||
} else {
|
} else {
|
||||||
HasGenericParams::No
|
ConstantHasGenerics::No
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|this| {
|
|this| {
|
||||||
|
@ -1945,6 +1945,16 @@ impl<'a> Resolver<'a> {
|
|||||||
def_id.as_local().map(|def_id| self.source_span[def_id])
|
def_id.as_local().map(|def_id| self.source_span[def_id])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the name of the given `DefId`.
|
||||||
|
#[inline]
|
||||||
|
pub fn opt_name(&self, def_id: DefId) -> Option<Symbol> {
|
||||||
|
let def_key = match def_id.as_local() {
|
||||||
|
Some(def_id) => self.definitions.def_key(def_id),
|
||||||
|
None => self.cstore().def_key(def_id),
|
||||||
|
};
|
||||||
|
def_key.get_opt_name()
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if an expression refers to a function marked with
|
/// Checks if an expression refers to a function marked with
|
||||||
/// `#[rustc_legacy_const_generics]` and returns the argument index list
|
/// `#[rustc_legacy_const_generics]` and returns the argument index list
|
||||||
/// from the attribute.
|
/// from the attribute.
|
||||||
|
@ -982,93 +982,6 @@ impl SourceMap {
|
|||||||
self.files().iter().fold(0, |a, f| a + f.count_lines())
|
self.files().iter().fold(0, |a, f| a + f.count_lines())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
|
|
||||||
let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?;
|
|
||||||
if let Ok(snippet) = self.span_to_snippet(prev_span) {
|
|
||||||
debug!(
|
|
||||||
"generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
|
|
||||||
span, prev_span, snippet
|
|
||||||
);
|
|
||||||
|
|
||||||
if snippet.is_empty() {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let len = snippet
|
|
||||||
.find(|c: char| !c.is_alphanumeric() && c != '_')
|
|
||||||
.expect("no label after fn");
|
|
||||||
Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes the span of a type parameter in a function signature and try to generate a span for
|
|
||||||
/// the function name (with generics) and a new snippet for this span with the pointed type
|
|
||||||
/// parameter as a new local type parameter.
|
|
||||||
///
|
|
||||||
/// For instance:
|
|
||||||
/// ```rust,ignore (pseudo-Rust)
|
|
||||||
/// // Given span
|
|
||||||
/// fn my_function(param: T)
|
|
||||||
/// // ^ Original span
|
|
||||||
///
|
|
||||||
/// // Result
|
|
||||||
/// fn my_function(param: T)
|
|
||||||
/// // ^^^^^^^^^^^ Generated span with snippet `my_function<T>`
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Attention: The method used is very fragile since it essentially duplicates the work of the
|
|
||||||
/// parser. If you need to use this function or something similar, please consider updating the
|
|
||||||
/// `SourceMap` functions and this function to something more robust.
|
|
||||||
pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
|
|
||||||
// Try to extend the span to the previous "fn" keyword to retrieve the function
|
|
||||||
// signature.
|
|
||||||
if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
|
|
||||||
if let Ok(snippet) = self.span_to_snippet(sugg_span) {
|
|
||||||
// Consume the function name.
|
|
||||||
let mut offset = snippet
|
|
||||||
.find(|c: char| !c.is_alphanumeric() && c != '_')
|
|
||||||
.expect("no label after fn");
|
|
||||||
|
|
||||||
// Consume the generics part of the function signature.
|
|
||||||
let mut bracket_counter = 0;
|
|
||||||
let mut last_char = None;
|
|
||||||
for c in snippet[offset..].chars() {
|
|
||||||
match c {
|
|
||||||
'<' => bracket_counter += 1,
|
|
||||||
'>' => bracket_counter -= 1,
|
|
||||||
'(' => {
|
|
||||||
if bracket_counter == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
offset += c.len_utf8();
|
|
||||||
last_char = Some(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust the suggestion span to encompass the function name with its generics.
|
|
||||||
let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32));
|
|
||||||
|
|
||||||
// Prepare the new suggested snippet to append the type parameter that triggered
|
|
||||||
// the error in the generics of the function signature.
|
|
||||||
let mut new_snippet = if last_char == Some('>') {
|
|
||||||
format!("{}, ", &snippet[..(offset - '>'.len_utf8())])
|
|
||||||
} else {
|
|
||||||
format!("{}<", &snippet[..offset])
|
|
||||||
};
|
|
||||||
new_snippet
|
|
||||||
.push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string()));
|
|
||||||
new_snippet.push('>');
|
|
||||||
|
|
||||||
return Some((sugg_span, new_snippet));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
|
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
|
||||||
source_file.add_external_src(|| {
|
source_file.add_external_src(|| {
|
||||||
match source_file.name {
|
match source_file.name {
|
||||||
|
@ -280,6 +280,7 @@ symbols! {
|
|||||||
StructuralPartialEq,
|
StructuralPartialEq,
|
||||||
SubdiagnosticMessage,
|
SubdiagnosticMessage,
|
||||||
Sync,
|
Sync,
|
||||||
|
T,
|
||||||
Target,
|
Target,
|
||||||
ToOwned,
|
ToOwned,
|
||||||
ToString,
|
ToString,
|
||||||
|
@ -473,9 +473,6 @@ pub fn impossible_predicates<'tcx>(
|
|||||||
debug!("impossible_predicates(predicates={:?})", predicates);
|
debug!("impossible_predicates(predicates={:?})", predicates);
|
||||||
|
|
||||||
let result = tcx.infer_ctxt().enter(|infcx| {
|
let result = tcx.infer_ctxt().enter(|infcx| {
|
||||||
// HACK: Set tainted by errors to gracefully exit in case of overflow.
|
|
||||||
infcx.set_tainted_by_errors();
|
|
||||||
|
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let ocx = ObligationCtxt::new(&infcx);
|
let ocx = ObligationCtxt::new(&infcx);
|
||||||
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
|
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
|
||||||
|
@ -858,8 +858,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
{
|
{
|
||||||
if impl_synthetic != trait_synthetic {
|
if impl_synthetic != trait_synthetic {
|
||||||
let impl_def_id = impl_def_id.expect_local();
|
let impl_def_id = impl_def_id.expect_local();
|
||||||
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id);
|
let impl_span = tcx.def_span(impl_def_id);
|
||||||
let impl_span = tcx.hir().span(impl_hir_id);
|
|
||||||
let trait_span = tcx.def_span(trait_def_id);
|
let trait_span = tcx.def_span(trait_def_id);
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
@ -878,17 +877,16 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
// try taking the name from the trait impl
|
// try taking the name from the trait impl
|
||||||
// FIXME: this is obviously suboptimal since the name can already be used
|
// FIXME: this is obviously suboptimal since the name can already be used
|
||||||
// as another generic argument
|
// as another generic argument
|
||||||
let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?;
|
let new_name = tcx.opt_item_name(trait_def_id)?;
|
||||||
let trait_m = trait_m.def_id.as_local()?;
|
let trait_m = trait_m.def_id.as_local()?;
|
||||||
let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m });
|
let trait_m = tcx.hir().expect_trait_item(trait_m);
|
||||||
|
|
||||||
let impl_m = impl_m.def_id.as_local()?;
|
let impl_m = impl_m.def_id.as_local()?;
|
||||||
let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
|
let impl_m = tcx.hir().expect_impl_item(impl_m);
|
||||||
|
|
||||||
// in case there are no generics, take the spot between the function name
|
// in case there are no generics, take the spot between the function name
|
||||||
// and the opening paren of the argument list
|
// and the opening paren of the argument list
|
||||||
let new_generics_span =
|
let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
|
||||||
tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi();
|
|
||||||
// in case there are generics, just replace them
|
// in case there are generics, just replace them
|
||||||
let generics_span =
|
let generics_span =
|
||||||
impl_m.generics.span.substitute_dummy(new_generics_span);
|
impl_m.generics.span.substitute_dummy(new_generics_span);
|
||||||
@ -900,7 +898,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
"try changing the `impl Trait` argument to a generic parameter",
|
"try changing the `impl Trait` argument to a generic parameter",
|
||||||
vec![
|
vec![
|
||||||
// replace `impl Trait` with `T`
|
// replace `impl Trait` with `T`
|
||||||
(impl_span, new_name),
|
(impl_span, new_name.to_string()),
|
||||||
// replace impl method generics with trait method generics
|
// replace impl method generics with trait method generics
|
||||||
// This isn't quite right, as users might have changed the names
|
// This isn't quite right, as users might have changed the names
|
||||||
// of the generics, but it works for the common case
|
// of the generics, but it works for the common case
|
||||||
@ -917,7 +915,7 @@ fn compare_synthetic_generics<'tcx>(
|
|||||||
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
|
err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
|
||||||
(|| {
|
(|| {
|
||||||
let impl_m = impl_m.def_id.as_local()?;
|
let impl_m = impl_m.def_id.as_local()?;
|
||||||
let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
|
let impl_m = tcx.hir().expect_impl_item(impl_m);
|
||||||
let input_tys = match impl_m.kind {
|
let input_tys = match impl_m.kind {
|
||||||
hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
|
hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -1556,7 +1556,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let mut error_happened = false;
|
let mut error_happened = false;
|
||||||
|
|
||||||
// Type-check each field.
|
// Type-check each field.
|
||||||
for field in ast_fields {
|
for (idx, field) in ast_fields.iter().enumerate() {
|
||||||
let ident = tcx.adjust_ident(field.ident, variant.def_id);
|
let ident = tcx.adjust_ident(field.ident, variant.def_id);
|
||||||
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
|
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
|
||||||
seen_fields.insert(ident, field.span);
|
seen_fields.insert(ident, field.span);
|
||||||
@ -1594,7 +1594,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
// Make sure to give a type to the field even if there's
|
// Make sure to give a type to the field even if there's
|
||||||
// an error, so we can continue type-checking.
|
// an error, so we can continue type-checking.
|
||||||
self.check_expr_coercable_to_type(&field.expr, field_type, None);
|
let ty = self.check_expr_with_hint(&field.expr, field_type);
|
||||||
|
let (_, diag) =
|
||||||
|
self.demand_coerce_diag(&field.expr, ty, field_type, None, AllowTwoPhase::No);
|
||||||
|
|
||||||
|
if let Some(mut diag) = diag {
|
||||||
|
if idx == ast_fields.len() - 1 && remaining_fields.is_empty() {
|
||||||
|
self.suggest_fru_from_range(field, variant, substs, &mut diag);
|
||||||
|
}
|
||||||
|
diag.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the programmer specified correct number of fields.
|
// Make sure the programmer specified correct number of fields.
|
||||||
@ -1822,25 +1831,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
|
err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}"));
|
||||||
|
|
||||||
// If the last field is a range literal, but it isn't supposed to be, then they probably
|
if let Some(last) = ast_fields.last() {
|
||||||
// meant to use functional update syntax.
|
self.suggest_fru_from_range(last, variant, substs, &mut err);
|
||||||
//
|
}
|
||||||
|
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the last field is a range literal, but it isn't supposed to be, then they probably
|
||||||
|
/// meant to use functional update syntax.
|
||||||
|
fn suggest_fru_from_range(
|
||||||
|
&self,
|
||||||
|
last_expr_field: &hir::ExprField<'tcx>,
|
||||||
|
variant: &ty::VariantDef,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
) {
|
||||||
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
|
// I don't use 'is_range_literal' because only double-sided, half-open ranges count.
|
||||||
if let Some((
|
if let ExprKind::Struct(
|
||||||
last,
|
|
||||||
ExprKind::Struct(
|
|
||||||
QPath::LangItem(LangItem::Range, ..),
|
QPath::LangItem(LangItem::Range, ..),
|
||||||
&[ref range_start, ref range_end],
|
&[ref range_start, ref range_end],
|
||||||
_,
|
_,
|
||||||
),
|
) = last_expr_field.expr.kind
|
||||||
)) = ast_fields.last().map(|last| (last, &last.expr.kind)) &&
|
&& let variant_field =
|
||||||
let variant_field =
|
variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident)
|
||||||
variant.fields.iter().find(|field| field.ident(self.tcx) == last.ident) &&
|
&& let range_def_id = self.tcx.lang_items().range_struct()
|
||||||
let range_def_id = self.tcx.lang_items().range_struct() &&
|
&& variant_field
|
||||||
variant_field
|
.and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
|
||||||
.and_then(|field| field.ty(self.tcx, substs).ty_adt_def())
|
.map(|adt| adt.did())
|
||||||
.map(|adt| adt.did())
|
!= range_def_id
|
||||||
!= range_def_id
|
|
||||||
{
|
{
|
||||||
let instead = self
|
let instead = self
|
||||||
.tcx
|
.tcx
|
||||||
@ -1856,8 +1875,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Report an error for a struct field expression when there are invisible fields.
|
/// Report an error for a struct field expression when there are invisible fields.
|
||||||
|
@ -1136,7 +1136,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
opt_ty.unwrap_or_else(|| self.next_float_var())
|
opt_ty.unwrap_or_else(|| self.next_float_var())
|
||||||
}
|
}
|
||||||
ast::LitKind::Bool(_) => tcx.types.bool,
|
ast::LitKind::Bool(_) => tcx.types.bool,
|
||||||
ast::LitKind::Err(_) => tcx.ty_error(),
|
ast::LitKind::Err => tcx.ty_error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,10 +73,8 @@ impl UnixListener {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
|
||||||
let (addr, len) = sockaddr_un(path.as_ref())?;
|
let (addr, len) = sockaddr_un(path.as_ref())?;
|
||||||
#[cfg(target_os = "linux")]
|
const backlog: libc::c_int =
|
||||||
const backlog: libc::c_int = -1;
|
if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 };
|
||||||
#[cfg(not(target_os = "linux"))]
|
|
||||||
const backlog: libc::c_int = 128;
|
|
||||||
|
|
||||||
cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
|
cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?;
|
||||||
cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
|
cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?;
|
||||||
|
@ -4,7 +4,7 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn foo<const X: u32>() {
|
LL | fn foo<const X: u32>() {
|
||||||
| - const parameter from outer function
|
| - const parameter from outer function
|
||||||
LL | fn bar() -> u32 {
|
LL | fn bar() -> u32 {
|
||||||
| --- try adding a local generic parameter in this method instead
|
| - help: try using a local generic parameter instead: `<X>`
|
||||||
LL | X
|
LL | X
|
||||||
| ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn foo<T>(x: T) {
|
LL | fn foo<T>(x: T) {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
|
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
|
||||||
| --------------------------- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `bfnr<U, V: Baz<U>, W: Fn(), T>`
|
| help: try using a local generic parameter instead: `T,`
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/E0401.rs:9:16
|
--> $DIR/E0401.rs:9:16
|
||||||
@ -15,7 +15,7 @@ LL | fn foo<T>(x: T) {
|
|||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
...
|
...
|
||||||
LL | fn baz<U,
|
LL | fn baz<U,
|
||||||
| --- try adding a local generic parameter in this method instead
|
| - help: try using a local generic parameter instead: `T,`
|
||||||
...
|
...
|
||||||
LL | (y: T) {
|
LL | (y: T) {
|
||||||
| ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
|
@ -5,9 +5,9 @@ LL | impl<T> Struct<T> {
|
|||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | const CONST: fn() = || {
|
LL | const CONST: fn() = || {
|
||||||
LL | struct _Obligation where T:;
|
LL | struct _Obligation where T:;
|
||||||
| ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
|
|
| |
|
||||||
= help: try using a local generic parameter instead
|
| help: try using a local generic parameter instead: `<T>`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -2,10 +2,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
--> $DIR/issue-3214.rs:3:12
|
--> $DIR/issue-3214.rs:3:12
|
||||||
|
|
|
|
||||||
LL | fn foo<T>() {
|
LL | fn foo<T>() {
|
||||||
| --- - type parameter from outer function
|
| - type parameter from outer function
|
||||||
| |
|
|
||||||
| try adding a local generic parameter in this method instead
|
|
||||||
LL | struct Foo {
|
LL | struct Foo {
|
||||||
|
| - help: try using a local generic parameter instead: `<T>`
|
||||||
LL | x: T,
|
LL | x: T,
|
||||||
| ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
--> $DIR/issue-5997-enum.rs:2:16
|
--> $DIR/issue-5997-enum.rs:2:16
|
||||||
|
|
|
|
||||||
LL | fn f<Z>() -> bool {
|
LL | fn f<Z>() -> bool {
|
||||||
| - - type parameter from outer function
|
| - type parameter from outer function
|
||||||
| |
|
|
||||||
| try adding a local generic parameter in this method instead
|
|
||||||
LL | enum E { V(Z) }
|
LL | enum E { V(Z) }
|
||||||
| ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
|
| |
|
||||||
|
| help: try using a local generic parameter instead: `<Z>`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
--> $DIR/issue-5997-struct.rs:2:14
|
--> $DIR/issue-5997-struct.rs:2:14
|
||||||
|
|
|
|
||||||
LL | fn f<T>() -> bool {
|
LL | fn f<T>() -> bool {
|
||||||
| - - type parameter from outer function
|
| - type parameter from outer function
|
||||||
| |
|
|
||||||
| try adding a local generic parameter in this method instead
|
|
||||||
LL | struct S(T);
|
LL | struct S(T);
|
||||||
| ^ use of generic parameter from outer function
|
| -^ use of generic parameter from outer function
|
||||||
|
| |
|
||||||
|
| help: try using a local generic parameter instead: `<T>`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn hd<U>(v: Vec<U> ) -> U {
|
LL | fn hd<U>(v: Vec<U> ) -> U {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn hd1(w: [U]) -> U { return w[0]; }
|
LL | fn hd1(w: [U]) -> U { return w[0]; }
|
||||||
| --- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `hd1<U>`
|
| help: try using a local generic parameter instead: `<U>`
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/nested-ty-params.rs:3:23
|
--> $DIR/nested-ty-params.rs:3:23
|
||||||
@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn hd<U>(v: Vec<U> ) -> U {
|
LL | fn hd<U>(v: Vec<U> ) -> U {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn hd1(w: [U]) -> U { return w[0]; }
|
LL | fn hd1(w: [U]) -> U { return w[0]; }
|
||||||
| --- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `hd1<U>`
|
| help: try using a local generic parameter instead: `<U>`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn foo<T>() {
|
LL | fn foo<T>() {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn bar(b: T) { }
|
LL | fn bar(b: T) { }
|
||||||
| --- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `bar<T>`
|
| help: try using a local generic parameter instead: `<T>`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -3,22 +3,22 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
|
|
|
|
||||||
LL | fn siphash<T>() {
|
LL | fn siphash<T>() {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
...
|
LL |
|
||||||
|
LL | trait U {
|
||||||
|
| - help: try using a local generic parameter instead: `<T>`
|
||||||
LL | fn g(&self, x: T) -> T;
|
LL | fn g(&self, x: T) -> T;
|
||||||
| - ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
| |
|
|
||||||
| help: try using a local generic parameter instead: `g<T>`
|
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/issue-3021-c.rs:4:30
|
--> $DIR/issue-3021-c.rs:4:30
|
||||||
|
|
|
|
||||||
LL | fn siphash<T>() {
|
LL | fn siphash<T>() {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
...
|
LL |
|
||||||
|
LL | trait U {
|
||||||
|
| - help: try using a local generic parameter instead: `<T>`
|
||||||
LL | fn g(&self, x: T) -> T;
|
LL | fn g(&self, x: T) -> T;
|
||||||
| - ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
| |
|
|
||||||
| help: try using a local generic parameter instead: `g<T>`
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | trait TraitA<A> {
|
LL | trait TraitA<A> {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn outer(&self) {
|
LL | fn outer(&self) {
|
||||||
| ----- try adding a local generic parameter in this method instead
|
|
||||||
LL | enum Foo<B> {
|
LL | enum Foo<B> {
|
||||||
|
| - help: try using a local generic parameter instead: `A,`
|
||||||
LL | Variance(A)
|
LL | Variance(A)
|
||||||
| ^ use of generic parameter from outer function
|
| ^ use of generic parameter from outer function
|
||||||
|
|
||||||
@ -15,9 +15,10 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | trait TraitB<A> {
|
LL | trait TraitB<A> {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn outer(&self) {
|
LL | fn outer(&self) {
|
||||||
| ----- try adding a local generic parameter in this method instead
|
|
||||||
LL | struct Foo<B>(A);
|
LL | struct Foo<B>(A);
|
||||||
| ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
|
| |
|
||||||
|
| help: try using a local generic parameter instead: `A,`
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
|
--> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
|
||||||
@ -25,9 +26,10 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | trait TraitC<A> {
|
LL | trait TraitC<A> {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn outer(&self) {
|
LL | fn outer(&self) {
|
||||||
| ----- try adding a local generic parameter in this method instead
|
|
||||||
LL | struct Foo<B> { a: A }
|
LL | struct Foo<B> { a: A }
|
||||||
| ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
|
| |
|
||||||
|
| help: try using a local generic parameter instead: `A,`
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
|
--> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
|
||||||
@ -36,9 +38,9 @@ LL | trait TraitD<A> {
|
|||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn outer(&self) {
|
LL | fn outer(&self) {
|
||||||
LL | fn foo<B>(a: A) { }
|
LL | fn foo<B>(a: A) { }
|
||||||
| ------ ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `foo<B, A>`
|
| help: try using a local generic parameter instead: `A,`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
@ -6,11 +6,29 @@ struct A {
|
|||||||
d: usize,
|
d: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn a() {
|
||||||
let q = A { c: 5, .. Default::default() };
|
let q = A { c: 5,..Default::default() };
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| ERROR missing fields
|
//~| ERROR missing fields
|
||||||
//~| HELP separate the last named field with a comma
|
//~| HELP separate the last named field with a comma
|
||||||
let r = A { c: 5, .. Default::default() };
|
let r = A { c: 5, ..Default::default() };
|
||||||
assert_eq!(q, r);
|
assert_eq!(q, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Eq, PartialEq)]
|
||||||
|
struct B {
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let q = B { b: 1,..Default::default() };
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP separate the last named field with a comma
|
||||||
|
let r = B { b: 1 };
|
||||||
|
assert_eq!(q, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
}
|
||||||
|
@ -6,11 +6,29 @@ struct A {
|
|||||||
d: usize,
|
d: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn a() {
|
||||||
let q = A { c: 5 .. Default::default() };
|
let q = A { c: 5..Default::default() };
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| ERROR missing fields
|
//~| ERROR missing fields
|
||||||
//~| HELP separate the last named field with a comma
|
//~| HELP separate the last named field with a comma
|
||||||
let r = A { c: 5, .. Default::default() };
|
let r = A { c: 5, ..Default::default() };
|
||||||
assert_eq!(q, r);
|
assert_eq!(q, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Eq, PartialEq)]
|
||||||
|
struct B {
|
||||||
|
b: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn b() {
|
||||||
|
let q = B { b: 1..Default::default() };
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
//~| HELP separate the last named field with a comma
|
||||||
|
let r = B { b: 1 };
|
||||||
|
assert_eq!(q, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/struct-record-suggestion.rs:10:20
|
--> $DIR/struct-record-suggestion.rs:10:20
|
||||||
|
|
|
|
||||||
LL | let q = A { c: 5 .. Default::default() };
|
LL | let q = A { c: 5..Default::default() };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
|
| ^^^^^^^^^^^^^^^^^^^^^ expected `u64`, found struct `std::ops::Range`
|
||||||
|
|
|
|
||||||
= note: expected type `u64`
|
= note: expected type `u64`
|
||||||
found struct `std::ops::Range<{integer}>`
|
found struct `std::ops::Range<{integer}>`
|
||||||
@ -10,15 +10,28 @@ LL | let q = A { c: 5 .. Default::default() };
|
|||||||
error[E0063]: missing fields `b` and `d` in initializer of `A`
|
error[E0063]: missing fields `b` and `d` in initializer of `A`
|
||||||
--> $DIR/struct-record-suggestion.rs:10:13
|
--> $DIR/struct-record-suggestion.rs:10:13
|
||||||
|
|
|
|
||||||
LL | let q = A { c: 5 .. Default::default() };
|
LL | let q = A { c: 5..Default::default() };
|
||||||
| ^ missing `b` and `d`
|
| ^ missing `b` and `d`
|
||||||
|
|
|
|
||||||
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
||||||
|
|
|
|
||||||
LL | let q = A { c: 5, .. Default::default() };
|
LL | let q = A { c: 5,..Default::default() };
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/struct-record-suggestion.rs:24:20
|
||||||
|
|
|
||||||
|
LL | let q = B { b: 1..Default::default() };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::ops::Range`
|
||||||
|
|
|
||||||
|
= note: expected type `u32`
|
||||||
|
found struct `std::ops::Range<{integer}>`
|
||||||
|
help: to set the remaining fields from `Default::default()`, separate the last named field with a comma
|
||||||
|
|
|
||||||
|
LL | let q = B { b: 1,..Default::default() };
|
||||||
|
| +
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0063, E0308.
|
Some errors have detailed explanations: E0063, E0308.
|
||||||
For more information about an error, try `rustc --explain E0063`.
|
For more information about an error, try `rustc --explain E0063`.
|
||||||
|
@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn foo<T>(x: T) {
|
LL | fn foo<T>(x: T) {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
|
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
|
||||||
| --- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `bar<T>`
|
| help: try using a local generic parameter instead: `<T>`
|
||||||
|
|
||||||
error[E0401]: can't use generic parameters from outer function
|
error[E0401]: can't use generic parameters from outer function
|
||||||
--> $DIR/type-arg-out-of-scope.rs:3:35
|
--> $DIR/type-arg-out-of-scope.rs:3:35
|
||||||
@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function
|
|||||||
LL | fn foo<T>(x: T) {
|
LL | fn foo<T>(x: T) {
|
||||||
| - type parameter from outer function
|
| - type parameter from outer function
|
||||||
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
|
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
|
||||||
| --- ^ use of generic parameter from outer function
|
| - ^ use of generic parameter from outer function
|
||||||
| |
|
| |
|
||||||
| help: try using a local generic parameter instead: `bar<T>`
|
| help: try using a local generic parameter instead: `<T>`
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ impl<'a> NormalizedPat<'a> {
|
|||||||
LitKind::Char(val) => Self::LitInt(val.into()),
|
LitKind::Char(val) => Self::LitInt(val.into()),
|
||||||
LitKind::Int(val, _) => Self::LitInt(val),
|
LitKind::Int(val, _) => Self::LitInt(val),
|
||||||
LitKind::Bool(val) => Self::LitBool(val),
|
LitKind::Bool(val) => Self::LitBool(val),
|
||||||
LitKind::Float(..) | LitKind::Err(_) => Self::Wild,
|
LitKind::Float(..) | LitKind::Err => Self::Wild,
|
||||||
},
|
},
|
||||||
_ => Self::Wild,
|
_ => Self::Wild,
|
||||||
},
|
},
|
||||||
|
@ -276,7 +276,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||||||
match lit.value.node {
|
match lit.value.node {
|
||||||
LitKind::Bool(val) => kind!("Bool({val:?})"),
|
LitKind::Bool(val) => kind!("Bool({val:?})"),
|
||||||
LitKind::Char(c) => kind!("Char({c:?})"),
|
LitKind::Char(c) => kind!("Char({c:?})"),
|
||||||
LitKind::Err(val) => kind!("Err({val})"),
|
LitKind::Err => kind!("Err"),
|
||||||
LitKind::Byte(b) => kind!("Byte({b})"),
|
LitKind::Byte(b) => kind!("Byte({b})"),
|
||||||
LitKind::Int(i, suffix) => {
|
LitKind::Int(i, suffix) => {
|
||||||
let int_ty = match suffix {
|
let int_ty = match suffix {
|
||||||
|
@ -45,7 +45,7 @@ pub enum Constant {
|
|||||||
/// A reference
|
/// A reference
|
||||||
Ref(Box<Constant>),
|
Ref(Box<Constant>),
|
||||||
/// A literal with syntax error.
|
/// A literal with syntax error.
|
||||||
Err(Symbol),
|
Err,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Constant {
|
impl PartialEq for Constant {
|
||||||
@ -118,9 +118,7 @@ impl Hash for Constant {
|
|||||||
Self::Ref(ref r) => {
|
Self::Ref(ref r) => {
|
||||||
r.hash(state);
|
r.hash(state);
|
||||||
},
|
},
|
||||||
Self::Err(ref s) => {
|
Self::Err => {},
|
||||||
s.hash(state);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +192,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
|
|||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
},
|
},
|
||||||
LitKind::Bool(b) => Constant::Bool(b),
|
LitKind::Bool(b) => Constant::Bool(b),
|
||||||
LitKind::Err(s) => Constant::Err(s),
|
LitKind::Err => Constant::Err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user