Auto merge of #127892 - tgross35:rollup-7j9wkzc, r=tgross35

Rollup of 9 pull requests

Successful merges:

 - #127542 ([`macro_metavar_expr_concat`] Add support for literals)
 - #127652 (Unignore cg_gcc fmt)
 - #127664 (Fix precise capturing suggestion for hidden regions when we have APITs)
 - #127806 (Some parser improvements)
 - #127828 (Commonize `uname -m` results for `aarch64` in docker runner)
 - #127845 (unix: break `stack_overflow::install_main_guard` into smaller fn)
 - #127859 (ptr::metadata: avoid references to extern types)
 - #127861 (Document the column numbers for the dbg! macro)
 - #127875 (style-guide: Clarify version-sorting)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-07-18 03:43:44 +00:00
commit 4bb2f27861
33 changed files with 758 additions and 364 deletions

View File

@ -699,8 +699,7 @@ impl Token {
false
}
/// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
/// That is, is this a pre-parsed expression dropped into the token stream
/// Is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
if let Interpolated(nt) = &self.kind

View File

@ -1 +1,3 @@
version = "Two"
use_small_heuristics = "Max"
merge_derives = false

View File

@ -34,7 +34,7 @@ impl Args {
"--out-path" => match args.next() {
Some(path) if !path.is_empty() => out_path = Some(path),
_ => {
return Err("Expected an argument after `--out-path`, found nothing".into())
return Err("Expected an argument after `--out-path`, found nothing".into());
}
},
"--help" => {

View File

@ -54,7 +54,7 @@ impl ConfigFile {
config.gcc_path = Some(value.as_str().to_string())
}
("gcc-path", _) => {
return failed_config_parsing(config_file, "Expected a string for `gcc-path`")
return failed_config_parsing(config_file, "Expected a string for `gcc-path`");
}
("download-gccjit", TomlValue::Boolean(value)) => {
config.download_gccjit = Some(*value)
@ -63,7 +63,7 @@ impl ConfigFile {
return failed_config_parsing(
config_file,
"Expected a boolean for `download-gccjit`",
)
);
}
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
}
@ -73,7 +73,7 @@ impl ConfigFile {
return failed_config_parsing(
config_file,
"At least one of `gcc-path` or `download-gccjit` value must be set",
)
);
}
(Some(_), Some(true)) => {
println!(
@ -144,7 +144,7 @@ impl ConfigInfo {
_ => {
return Err(
"Expected a value after `--target-triple`, found nothing".to_string()
)
);
}
},
"--out-dir" => match args.next() {
@ -158,7 +158,7 @@ impl ConfigInfo {
self.config_file = Some(arg.to_string());
}
_ => {
return Err("Expected a value after `--config-file`, found nothing".to_string())
return Err("Expected a value after `--config-file`, found nothing".to_string());
}
},
"--release-sysroot" => self.sysroot_release_channel = true,
@ -169,7 +169,7 @@ impl ConfigInfo {
self.cg_gcc_path = Some(arg.into());
}
_ => {
return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string())
return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string());
}
},
"--use-backend" => match args.next() {
@ -277,7 +277,7 @@ impl ConfigInfo {
self.gcc_path = match gcc_path {
Some(path) => path,
None => {
return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),))
return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),));
}
};
Ok(())

View File

@ -109,7 +109,7 @@ impl TestArg {
test_arg.flags.extend_from_slice(&["--features".into(), feature]);
}
_ => {
return Err("Expected an argument after `--features`, found nothing".into())
return Err("Expected an argument after `--features`, found nothing".into());
}
},
"--use-system-gcc" => {
@ -458,11 +458,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
.map_err(|error| format!("Failed to retrieve cargo path: {:?}", error))
.and_then(|cargo| {
let cargo = cargo.trim().to_owned();
if cargo.is_empty() {
Err(format!("`cargo` path is empty"))
} else {
Ok(cargo)
}
if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) }
})?;
let rustc = String::from_utf8(
run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?
@ -471,11 +467,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
.map_err(|error| format!("Failed to retrieve rustc path: {:?}", error))
.and_then(|rustc| {
let rustc = rustc.trim().to_owned();
if rustc.is_empty() {
Err(format!("`rustc` path is empty"))
} else {
Ok(rustc)
}
if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) }
})?;
let llvm_filecheck = match run_command_with_env(
&[

View File

@ -175,11 +175,7 @@ pub fn cargo_install(to_install: &str) -> Result<(), String> {
pub fn get_os_name() -> Result<String, String> {
let output = run_command(&[&"uname"], None)?;
let name = std::str::from_utf8(&output.stdout).unwrap_or("").trim().to_string();
if !name.is_empty() {
Ok(name)
} else {
Err("Failed to retrieve the OS name".to_string())
}
if !name.is_empty() { Ok(name) } else { Err("Failed to retrieve the OS name".to_string()) }
}
#[derive(Default, PartialEq)]

View File

@ -26,11 +26,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
} else {
false
};
if on_stack {
param.to_lvalue().get_address(None)
} else {
param.to_rvalue()
}
if on_stack { param.to_lvalue().get_address(None) } else { param.to_rvalue() }
}
}

View File

@ -858,11 +858,7 @@ fn modifier_to_gcc(
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
if modifier == Some('v') {
None
} else {
modifier
}
if modifier == Some('v') { None } else { modifier }
}
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
unreachable!("clobber-only")

View File

@ -1043,11 +1043,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let llty = place.layout.scalar_pair_element_gcc_type(self, i);
let load = self.load(llty, llptr, align);
scalar_load_metadata(self, load, scalar);
if scalar.is_bool() {
self.trunc(load, self.type_i1())
} else {
load
}
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
};
OperandValue::Pair(
@ -1795,18 +1791,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
let int_max = |signed: bool, int_width: u64| -> u128 {
let shift_amount = 128 - int_width;
if signed {
i128::MAX as u128 >> shift_amount
} else {
u128::MAX >> shift_amount
}
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
};
let int_min = |signed: bool, int_width: u64| -> i128 {
if signed {
i128::MIN >> (128 - int_width)
} else {
0
}
if signed { i128::MIN >> (128 - int_width) } else { 0 }
};
let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {

View File

@ -58,11 +58,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool {
impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
if type_is_pointer(typ) {
self.context.new_null(typ)
} else {
self.const_int(typ, 0)
}
if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
}
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {

View File

@ -119,6 +119,8 @@ impl MetaVarExpr {
}
}
/// Indicates what is placed in a `concat` parameter. For example, literals
/// (`${concat("foo", "bar")}`) or adhoc identifiers (`${concat(foo, bar)}`).
#[derive(Debug, Decodable, Encodable, PartialEq)]
pub(crate) enum MetaVarExprConcatElem {
/// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be

View File

@ -6,9 +6,10 @@ use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR};
use crate::mbe::{self, KleeneOp, MetaVarExpr};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::IdentIsRaw;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
use rustc_ast::token::{IdentIsRaw, Lit, LitKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::ExprKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult};
use rustc_parse::lexer::nfc_normalize;
@ -17,7 +18,7 @@ use rustc_session::parse::ParseSess;
use rustc_session::parse::SymbolGallery;
use rustc_span::hygiene::{LocalExpnId, Transparency};
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
use rustc_span::{with_metavar_spans, Span, SyntaxContext};
use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext};
use smallvec::{smallvec, SmallVec};
use std::mem;
@ -691,12 +692,12 @@ fn transcribe_metavar_expr<'a>(
MetaVarExpr::Concat(ref elements) => {
let mut concatenated = String::new();
for element in elements.into_iter() {
let string = match element {
MetaVarExprConcatElem::Ident(elem) => elem.to_string(),
MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(),
MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?,
let symbol = match element {
MetaVarExprConcatElem::Ident(elem) => elem.name,
MetaVarExprConcatElem::Literal(elem) => *elem,
MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?,
};
concatenated.push_str(&string);
concatenated.push_str(symbol.as_str());
}
let symbol = nfc_normalize(&concatenated);
let concatenated_span = visited_span();
@ -750,32 +751,42 @@ fn transcribe_metavar_expr<'a>(
Ok(())
}
/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree.
fn extract_ident<'a>(
/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
fn extract_var_symbol<'a>(
dcx: DiagCtxtHandle<'a>,
ident: Ident,
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
) -> PResult<'a, String> {
) -> PResult<'a, Symbol> {
if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
}
return Ok(nt_ident.to_string());
return Ok(nt_ident.name);
}
if let ParseNtResult::Tt(TokenTree::Token(
Token { kind: TokenKind::Ident(token_ident, is_raw), .. },
_,
)) = pnr
{
if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
if let TokenKind::Ident(symbol, is_raw) = kind {
if let IdentIsRaw::Yes = is_raw {
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
}
return Ok(*symbol);
}
return Ok(token_ident.to_string());
if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
return Ok(*symbol);
}
}
if let ParseNtResult::Nt(nt) = pnr
&& let Nonterminal::NtLiteral(expr) = &**nt
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
{
return Ok(*symbol);
}
}
Err(dcx.struct_span_err(
ident.span,
"`${concat(..)}` currently only accepts identifiers or meta-variables as parameters",
))
Err(dcx
.struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
.with_note("currently only string literals are supported")
.with_span(ident.span))
}

View File

@ -225,6 +225,8 @@ infer_outlives_content = lifetime of reference outlives lifetime of borrowed con
infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it
infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}`
infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
infer_prlf_defined_without_sub = the lifetime defined here...
infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
@ -387,6 +389,9 @@ infer_type_annotations_needed = {$source_kind ->
.label = type must be known at this point
infer_types_declared_different = these two types are declared with different lifetimes...
infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable
infer_where_copy_predicates = copy the `where` clause predicates from the trait
infer_where_remove = remove the `where` clause

View File

@ -1269,9 +1269,13 @@ fn suggest_precise_capturing<'tcx>(
captured_lifetime: ty::Region<'tcx>,
diag: &mut Diag<'_>,
) {
let hir::OpaqueTy { bounds, .. } =
let hir::OpaqueTy { bounds, origin, .. } =
tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
let hir::OpaqueTyOrigin::FnReturn(fn_def_id) = *origin else {
return;
};
let new_lifetime = Symbol::intern(&captured_lifetime.to_string());
if let Some((args, span)) = bounds.iter().find_map(|bound| match bound {
@ -1306,6 +1310,7 @@ fn suggest_precise_capturing<'tcx>(
let variances = tcx.variances_of(opaque_def_id);
let mut generics = tcx.generics_of(opaque_def_id);
let mut synthetics = vec![];
loop {
for param in &generics.own_params {
if variances[param.index as usize] == ty::Bivariant {
@ -1317,9 +1322,7 @@ fn suggest_precise_capturing<'tcx>(
captured_lifetimes.insert(param.name);
}
ty::GenericParamDefKind::Type { synthetic: true, .. } => {
// FIXME: We can't provide a good suggestion for
// `use<...>` if we have an APIT. Bail for now.
return;
synthetics.push((tcx.def_span(param.def_id), param.name));
}
ty::GenericParamDefKind::Type { .. }
| ty::GenericParamDefKind::Const { .. } => {
@ -1340,17 +1343,86 @@ fn suggest_precise_capturing<'tcx>(
return;
}
let concatenated_bounds = captured_lifetimes
.into_iter()
.chain(captured_non_lifetimes)
.map(|sym| sym.to_string())
.collect::<Vec<_>>()
.join(", ");
if synthetics.is_empty() {
let concatenated_bounds = captured_lifetimes
.into_iter()
.chain(captured_non_lifetimes)
.map(|sym| sym.to_string())
.collect::<Vec<_>>()
.join(", ");
diag.subdiagnostic(errors::AddPreciseCapturing::New {
span: tcx.def_span(opaque_def_id).shrink_to_hi(),
new_lifetime,
concatenated_bounds,
});
diag.subdiagnostic(errors::AddPreciseCapturing::New {
span: tcx.def_span(opaque_def_id).shrink_to_hi(),
new_lifetime,
concatenated_bounds,
});
} else {
let mut next_fresh_param = || {
["T", "U", "V", "W", "X", "Y", "A", "B", "C"]
.into_iter()
.map(Symbol::intern)
.chain((0..).map(|i| Symbol::intern(&format!("T{i}"))))
.find(|s| captured_non_lifetimes.insert(*s))
.unwrap()
};
let mut new_params = String::new();
let mut suggs = vec![];
let mut apit_spans = vec![];
for (i, (span, name)) in synthetics.into_iter().enumerate() {
apit_spans.push(span);
let fresh_param = next_fresh_param();
// Suggest renaming.
suggs.push((span, fresh_param.to_string()));
// Super jank. Turn `impl Trait` into `T: Trait`.
//
// This currently involves stripping the `impl` from the name of
// the parameter, since APITs are always named after how they are
// rendered in the AST. This sucks! But to recreate the bound list
// from the APIT itself would be miserable, so we're stuck with
// this for now!
if i > 0 {
new_params += ", ";
}
let name_as_bounds = name.as_str().trim_start_matches("impl").trim_start();
new_params += fresh_param.as_str();
new_params += ": ";
new_params += name_as_bounds;
}
let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
// This shouldn't happen, but don't ICE.
return;
};
// Add generics or concatenate to the end of the list.
suggs.push(if let Some(params_span) = generics.span_for_param_suggestion() {
(params_span, format!(", {new_params}"))
} else {
(generics.span, format!("<{new_params}>"))
});
let concatenated_bounds = captured_lifetimes
.into_iter()
.chain(captured_non_lifetimes)
.map(|sym| sym.to_string())
.collect::<Vec<_>>()
.join(", ");
suggs.push((
tcx.def_span(opaque_def_id).shrink_to_hi(),
format!(" + use<{concatenated_bounds}>"),
));
diag.subdiagnostic(errors::AddPreciseCapturingAndParams {
suggs,
new_lifetime,
apit_spans,
});
}
}
}

View File

@ -1609,3 +1609,25 @@ pub enum AddPreciseCapturing {
post: &'static str,
},
}
pub struct AddPreciseCapturingAndParams {
pub suggs: Vec<(Span, String)>,
pub new_lifetime: Symbol,
pub apit_spans: Vec<Span>,
}
impl Subdiagnostic for AddPreciseCapturingAndParams {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
diag.arg("new_lifetime", self.new_lifetime);
diag.multipart_suggestion_verbose(
fluent::infer_precise_capturing_new_but_apit,
self.suggs,
Applicability::MaybeIncorrect,
);
diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params);
}
}

View File

@ -785,23 +785,14 @@ impl<'a> Parser<'a> {
}
};
self.parse_and_disallow_postfix_after_cast(cast_expr)
}
/// Parses a postfix operators such as `.`, `?`, or index (`[]`) after a cast,
/// then emits an error and returns the newly parsed tree.
/// The resulting parse tree for `&x as T[0]` has a precedence of `((&x) as T)[0]`.
fn parse_and_disallow_postfix_after_cast(
&mut self,
cast_expr: P<Expr>,
) -> PResult<'a, P<Expr>> {
if let ExprKind::Type(_, _) = cast_expr.kind {
panic!("ExprKind::Type must not be parsed");
}
// Try to parse a postfix operator such as `.`, `?`, or index (`[]`)
// after a cast. If one is present, emit an error then return a valid
// parse tree; For something like `&x as T[0]` will be as if it was
// written `((&x) as T)[0]`.
let span = cast_expr.span;
let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
let with_postfix = self.parse_expr_dot_or_call_with(AttrVec::new(), cast_expr, span)?;
// Check if an illegal postfix operator has been added after the cast.
// If the resulting expression is not a cast, it is an illegal postfix operator.
@ -885,23 +876,63 @@ impl<'a> Parser<'a> {
self.collect_tokens_for_expr(attrs, |this, attrs| {
let base = this.parse_expr_bottom()?;
let span = this.interpolated_or_expr_span(&base);
this.parse_expr_dot_or_call_with(base, span, attrs)
this.parse_expr_dot_or_call_with(attrs, base, span)
})
}
pub(super) fn parse_expr_dot_or_call_with(
&mut self,
e0: P<Expr>,
lo: Span,
mut attrs: ast::AttrVec,
mut e: P<Expr>,
lo: Span,
) -> PResult<'a, P<Expr>> {
// Stitch the list of outer attributes onto the return value.
// A little bit ugly, but the best way given the current code
// structure
let res = ensure_sufficient_stack(
// this expr demonstrates the recursion it guards against
|| self.parse_expr_dot_or_call_with_(e0, lo),
);
let res = ensure_sufficient_stack(|| {
loop {
let has_question =
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
// We are using noexpect here because we don't expect a `?` directly after
// a `return` which could be suggested otherwise.
self.eat_noexpect(&token::Question)
} else {
self.eat(&token::Question)
};
if has_question {
// `expr?`
e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
continue;
}
let has_dot =
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
// We are using noexpect here because we don't expect a `.` directly after
// a `return` which could be suggested otherwise.
self.eat_noexpect(&token::Dot)
} else if self.token.kind == TokenKind::RArrow && self.may_recover() {
// Recovery for `expr->suffix`.
self.bump();
let span = self.prev_token.span;
self.dcx().emit_err(errors::ExprRArrowCall { span });
true
} else {
self.eat(&token::Dot)
};
if has_dot {
// expr.f
e = self.parse_dot_suffix_expr(lo, e)?;
continue;
}
if self.expr_is_complete(&e) {
return Ok(e);
}
e = match self.token.kind {
token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
_ => return Ok(e),
}
}
});
// Stitch the list of outer attributes onto the return value. A little
// bit ugly, but the best way given the current code structure.
if attrs.is_empty() {
res
} else {
@ -915,50 +946,6 @@ impl<'a> Parser<'a> {
}
}
fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
loop {
let has_question =
if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
// we are using noexpect here because we don't expect a `?` directly after a `return`
// which could be suggested otherwise
self.eat_noexpect(&token::Question)
} else {
self.eat(&token::Question)
};
if has_question {
// `expr?`
e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
continue;
}
let has_dot = if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
// we are using noexpect here because we don't expect a `.` directly after a `return`
// which could be suggested otherwise
self.eat_noexpect(&token::Dot)
} else if self.token.kind == TokenKind::RArrow && self.may_recover() {
// Recovery for `expr->suffix`.
self.bump();
let span = self.prev_token.span;
self.dcx().emit_err(errors::ExprRArrowCall { span });
true
} else {
self.eat(&token::Dot)
};
if has_dot {
// expr.f
e = self.parse_dot_suffix_expr(lo, e)?;
continue;
}
if self.expr_is_complete(&e) {
return Ok(e);
}
e = match self.token.kind {
token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
_ => return Ok(e),
}
}
}
pub(super) fn parse_dot_suffix_expr(
&mut self,
lo: Span,
@ -1388,7 +1375,7 @@ impl<'a> Parser<'a> {
/// Parses things like parenthesized exprs, macros, `return`, etc.
///
/// N.B., this does not parse outer attributes, and is private because it only works
/// correctly if called from `parse_dot_or_call_expr()`.
/// correctly if called from `parse_expr_dot_or_call`.
fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
maybe_recover_from_interpolated_ty_qpath!(self, true);

View File

@ -128,56 +128,41 @@ impl<'a> Parser<'a> {
Some(item.into_inner())
});
let item =
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
let item =
this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
Ok((item?, TrailingToken::None))
})?;
self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
let mut def = this.parse_defaultness();
let kind = this.parse_item_kind(
&mut attrs,
mac_allowed,
lo,
&vis,
&mut def,
fn_parse_mode,
Case::Sensitive,
)?;
if let Some((ident, kind)) = kind {
this.error_on_unconsumed_default(def, &kind);
let span = lo.to(this.prev_token.span);
let id = DUMMY_NODE_ID;
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
return Ok((Some(item), TrailingToken::None));
}
Ok(item)
}
// At this point, we have failed to parse an item.
if !matches!(vis.kind, VisibilityKind::Inherited) {
this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
}
fn parse_item_common_(
&mut self,
mut attrs: AttrVec,
mac_allowed: bool,
attrs_allowed: bool,
fn_parse_mode: FnParseMode,
) -> PResult<'a, Option<Item>> {
let lo = self.token.span;
let vis = self.parse_visibility(FollowedByType::No)?;
let mut def = self.parse_defaultness();
let kind = self.parse_item_kind(
&mut attrs,
mac_allowed,
lo,
&vis,
&mut def,
fn_parse_mode,
Case::Sensitive,
)?;
if let Some((ident, kind)) = kind {
self.error_on_unconsumed_default(def, &kind);
let span = lo.to(self.prev_token.span);
let id = DUMMY_NODE_ID;
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
return Ok(Some(item));
}
if let Defaultness::Default(span) = def {
this.dcx().emit_err(errors::DefaultNotFollowedByItem { span });
}
// At this point, we have failed to parse an item.
if !matches!(vis.kind, VisibilityKind::Inherited) {
self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
}
if let Defaultness::Default(span) = def {
self.dcx().emit_err(errors::DefaultNotFollowedByItem { span });
}
if !attrs_allowed {
self.recover_attrs_no_item(&attrs)?;
}
Ok(None)
if !attrs_allowed {
this.recover_attrs_no_item(&attrs)?;
}
Ok((None, TrailingToken::None))
})
}
/// Error in-case `default` was parsed in an in-appropriate context.

View File

@ -101,7 +101,6 @@ pub enum TrailingToken {
MaybeComma,
}
/// Like `maybe_whole_expr`, but for things other than expressions.
#[macro_export]
macro_rules! maybe_whole {
($p:expr, $constructor:ident, |$x:ident| $e:expr) => {

View File

@ -392,9 +392,9 @@ impl<'a> Parser<'a> {
// Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten.
if let Ok(expr) = snapshot
.parse_expr_dot_or_call_with(
AttrVec::new(),
self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr`
pat_span,
AttrVec::new(),
)
.map_err(|err| err.cancel())
{

View File

@ -164,7 +164,7 @@ impl<'a> Parser<'a> {
};
let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
this.parse_expr_dot_or_call_with(expr, lo, attrs)
this.parse_expr_dot_or_call_with(attrs, expr, lo)
})?;
// `DUMMY_SP` will get overwritten later in this function
Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), TrailingToken::None))
@ -206,7 +206,7 @@ impl<'a> Parser<'a> {
// Since none of the above applied, this is an expression statement macro.
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_expr_dot_or_call_with(e, lo, attrs)?;
let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
let e = self
.parse_expr_assoc_with(0, LhsExpr::Parsed { expr: e, starts_statement: false })?;
StmtKind::Expr(e)

View File

@ -5,6 +5,7 @@ use crate::hash::{Hash, Hasher};
use crate::intrinsics::aggregate_raw_ptr;
use crate::intrinsics::ptr_metadata;
use crate::marker::Freeze;
use crate::ptr::NonNull;
/// Provides the pointer metadata type of any pointed-to type.
///
@ -153,7 +154,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
/// compare equal (since identical vtables can be deduplicated within a codegen unit).
#[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: ?Sized> {
_vtable_ptr: &'static VTable,
_vtable_ptr: NonNull<VTable>,
_phantom: crate::marker::PhantomData<Dyn>,
}
@ -166,15 +167,18 @@ extern "C" {
}
impl<Dyn: ?Sized> DynMetadata<Dyn> {
/// One of the things that rustc_middle does with this being a lang item is
/// give it `FieldsShape::Primitive`, which means that as far as codegen can
/// tell, it *is* a reference, and thus doesn't have any fields.
/// That means we can't use field access, and have to transmute it instead.
/// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout
/// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead
/// it is a `FieldsShape::Primitive`. This means that the same type can have different layout
/// depending on whether it appears as the metadata field of a wide pointer or as a stand-alone
/// type, which understandably confuses codegen and leads to ICEs when trying to project to a
/// field of `DynMetadata`. To work around that issue, we use `transmute` instead of using a
/// field projection.
#[inline]
fn vtable_ptr(self) -> *const VTable {
// SAFETY: this layout assumption is hard-coded into the compiler.
// If it's somehow not a size match, the transmute will error.
unsafe { crate::mem::transmute::<Self, &'static VTable>(self) }
unsafe { crate::mem::transmute::<Self, *const VTable>(self) }
}
/// Returns the size of the type associated with this vtable.

View File

@ -230,7 +230,7 @@ macro_rules! eprintln {
/// ```rust
/// let a = 2;
/// let b = dbg!(a * 2) + 1;
/// // ^-- prints: [src/main.rs:2] a * 2 = 4
/// // ^-- prints: [src/main.rs:2:9] a * 2 = 4
/// assert_eq!(b, 5);
/// ```
///
@ -281,7 +281,7 @@ macro_rules! eprintln {
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:4] n.checked_sub(4) = None
/// [src/main.rs:2:22] n.checked_sub(4) = None
/// ```
///
/// Naive factorial implementation:
@ -301,15 +301,15 @@ macro_rules! eprintln {
/// This prints to [stderr]:
///
/// ```text,ignore
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = false
/// [src/main.rs:3] n <= 1 = true
/// [src/main.rs:4] 1 = 1
/// [src/main.rs:5] n * factorial(n - 1) = 2
/// [src/main.rs:5] n * factorial(n - 1) = 6
/// [src/main.rs:5] n * factorial(n - 1) = 24
/// [src/main.rs:11] factorial(4) = 24
/// [src/main.rs:2:8] n <= 1 = false
/// [src/main.rs:2:8] n <= 1 = false
/// [src/main.rs:2:8] n <= 1 = false
/// [src/main.rs:2:8] n <= 1 = true
/// [src/main.rs:3:9] 1 = 1
/// [src/main.rs:7:9] n * factorial(n - 1) = 2
/// [src/main.rs:7:9] n * factorial(n - 1) = 6
/// [src/main.rs:7:9] n * factorial(n - 1) = 24
/// [src/main.rs:9:1] factorial(4) = 24
/// ```
///
/// The `dbg!(..)` macro moves the input:

View File

@ -44,6 +44,7 @@ mod imp {
use crate::ops::Range;
use crate::ptr;
use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
use crate::sync::OnceLock;
use crate::sys::pal::unix::os;
use crate::thread;
@ -306,9 +307,8 @@ mod imp {
ret
}
unsafe fn get_stack_start_aligned() -> Option<*mut libc::c_void> {
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
let stackptr = get_stack_start()?;
fn stack_start_aligned(page_size: usize) -> Option<*mut libc::c_void> {
let stackptr = unsafe { get_stack_start()? };
let stackaddr = stackptr.addr();
// Ensure stackaddr is page aligned! A parent process might
@ -325,104 +325,133 @@ mod imp {
})
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard() -> Option<Range<usize>> {
let page_size = PAGE_SIZE.load(Ordering::Relaxed);
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
// Linux doesn't allocate the whole stack right away, and
// the kernel has its own stack-guard mechanism to fault
// when growing too close to an existing mapping. If we map
// our own guard, then the kernel starts enforcing a rather
// large gap above that, rendering much of the possible
// stack space useless. See #43052.
//
// Instead, we'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
let stackptr = get_stack_start_aligned()?;
let stackaddr = stackptr.addr();
Some(stackaddr - page_size..stackaddr)
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
// For the main thread, the musl's pthread_attr_getstack
// returns the current stack size, rather than maximum size
// it can eventually grow to. It cannot be used to determine
// the position of kernel's stack guard.
None
} else if cfg!(target_os = "freebsd") {
// FreeBSD's stack autogrows, and optionally includes a guard page
// at the bottom. If we try to remap the bottom of the stack
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
// the builtin guard page.
let stackptr = get_stack_start_aligned()?;
let guardaddr = stackptr.addr();
// Technically the number of guard pages is tunable and controlled
// by the security.bsd.stack_guard_page sysctl.
// By default it is 1, checking once is enough since it is
// a boot time config value.
static PAGES: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
let pages = PAGES.get_or_init(|| {
use crate::sys::weak::dlsym;
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
let mut guard: usize = 0;
let mut size = crate::mem::size_of_val(&guard);
let oid = crate::ffi::CStr::from_bytes_with_nul(
b"security.bsd.stack_guard_page\0",
)
.unwrap();
match sysctlbyname.get() {
Some(fcn) => {
if fcn(oid.as_ptr(), core::ptr::addr_of_mut!(guard) as *mut _, core::ptr::addr_of_mut!(size) as *mut _, crate::ptr::null_mut(), 0) == 0 {
guard
} else {
1
}
},
_ => 1,
}
});
Some(guardaddr..guardaddr + pages * page_size)
} else if cfg!(any(target_os = "openbsd", target_os = "netbsd")) {
// OpenBSD stack already includes a guard page, and stack is
// immutable.
// NetBSD stack includes the guard page.
//
// We'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
let stackptr = get_stack_start_aligned()?;
let stackaddr = stackptr.addr();
Some(stackaddr - page_size..stackaddr)
} else {
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
// stack overflow.
// Systems which enforce strict PAX MPROTECT do not allow
// to mprotect() a mapping with less restrictive permissions
// than the initial mmap() used, so we mmap() here with
// read/write permissions and only then mprotect() it to
// no permissions at all. See issue #50313.
let stackptr = get_stack_start_aligned()?;
let result = mmap64(
unsafe {
// this way someone on any unix-y OS can check that all these compile
if cfg!(all(target_os = "linux", not(target_env = "musl"))) {
install_main_guard_linux(page_size)
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
install_main_guard_linux_musl(page_size)
} else if cfg!(target_os = "freebsd") {
install_main_guard_freebsd(page_size)
} else if cfg!(any(target_os = "netbsd", target_os = "openbsd")) {
install_main_guard_bsds(page_size)
} else {
install_main_guard_default(page_size)
}
}
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard_linux(page_size: usize) -> Option<Range<usize>> {
// Linux doesn't allocate the whole stack right away, and
// the kernel has its own stack-guard mechanism to fault
// when growing too close to an existing mapping. If we map
// our own guard, then the kernel starts enforcing a rather
// large gap above that, rendering much of the possible
// stack space useless. See #43052.
//
// Instead, we'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
let stackptr = stack_start_aligned(page_size)?;
let stackaddr = stackptr.addr();
Some(stackaddr - page_size..stackaddr)
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard_linux_musl(_page_size: usize) -> Option<Range<usize>> {
// For the main thread, the musl's pthread_attr_getstack
// returns the current stack size, rather than maximum size
// it can eventually grow to. It cannot be used to determine
// the position of kernel's stack guard.
None
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard_freebsd(page_size: usize) -> Option<Range<usize>> {
// FreeBSD's stack autogrows, and optionally includes a guard page
// at the bottom. If we try to remap the bottom of the stack
// ourselves, FreeBSD's guard page moves upwards. So we'll just use
// the builtin guard page.
let stackptr = stack_start_aligned(page_size)?;
let guardaddr = stackptr.addr();
// Technically the number of guard pages is tunable and controlled
// by the security.bsd.stack_guard_page sysctl.
// By default it is 1, checking once is enough since it is
// a boot time config value.
static PAGES: OnceLock<usize> = OnceLock::new();
let pages = PAGES.get_or_init(|| {
use crate::sys::weak::dlsym;
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int);
let mut guard: usize = 0;
let mut size = mem::size_of_val(&guard);
let oid = c"security.bsd.stack_guard_page";
match sysctlbyname.get() {
Some(fcn) if unsafe {
fcn(oid.as_ptr(),
ptr::addr_of_mut!(guard).cast(),
ptr::addr_of_mut!(size),
ptr::null_mut(),
0) == 0
} => guard,
_ => 1,
}
});
Some(guardaddr..guardaddr + pages * page_size)
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard_bsds(page_size: usize) -> Option<Range<usize>> {
// OpenBSD stack already includes a guard page, and stack is
// immutable.
// NetBSD stack includes the guard page.
//
// We'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
let stackptr = stack_start_aligned(page_size)?;
let stackaddr = stackptr.addr();
Some(stackaddr - page_size..stackaddr)
}
#[forbid(unsafe_op_in_unsafe_fn)]
unsafe fn install_main_guard_default(page_size: usize) -> Option<Range<usize>> {
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
// stack overflow.
// Systems which enforce strict PAX MPROTECT do not allow
// to mprotect() a mapping with less restrictive permissions
// than the initial mmap() used, so we mmap() here with
// read/write permissions and only then mprotect() it to
// no permissions at all. See issue #50313.
let stackptr = stack_start_aligned(page_size)?;
let result = unsafe {
mmap64(
stackptr,
page_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-1,
0,
);
if result != stackptr || result == MAP_FAILED {
panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
}
let result = mprotect(stackptr, page_size, PROT_NONE);
if result != 0 {
panic!("failed to protect the guard page: {}", io::Error::last_os_error());
}
let guardaddr = stackptr.addr();
Some(guardaddr..guardaddr + page_size)
)
};
if result != stackptr || result == MAP_FAILED {
panic!("failed to allocate a guard page: {}", io::Error::last_os_error());
}
let result = unsafe { mprotect(stackptr, page_size, PROT_NONE) };
if result != 0 {
panic!("failed to protect the guard page: {}", io::Error::last_os_error());
}
let guardaddr = stackptr.addr();
Some(guardaddr..guardaddr + page_size)
}
#[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))]

View File

@ -31,7 +31,6 @@ ignore = [
"library/backtrace",
"library/portable-simd",
"library/stdarch",
"compiler/rustc_codegen_gcc",
"src/doc/book",
"src/doc/edition-guide",
"src/doc/embedded-book",
@ -50,4 +49,8 @@ ignore = [
# These are ignored by a standard cargo fmt run.
"compiler/rustc_codegen_cranelift/scripts",
"compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024
"compiler/rustc_codegen_gcc/tests",
# Code automatically generated and included.
"compiler/rustc_codegen_gcc/src/intrinsic/archs.rs",
"compiler/rustc_codegen_gcc/example",
]

View File

@ -27,8 +27,11 @@ do
shift
done
# MacOS reports "arm64" while Linux reports "aarch64". Commonize this.
machine="$(uname -m | sed 's/arm64/aarch64/')"
script_dir="`dirname $script`"
docker_dir="${script_dir}/host-$(uname -m)"
docker_dir="${script_dir}/host-${machine}"
ci_dir="`dirname $script_dir`"
src_dir="`dirname $ci_dir`"
root_dir="`dirname $src_dir`"
@ -68,7 +71,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
# Include the architecture in the hash key, since our Linux CI does not
# only run in x86_64 machines.
uname -m >> $hash_key
echo "$machine" >> $hash_key
# Include cache version. Can be used to manually bust the Docker cache.
echo "2" >> $hash_key
@ -178,7 +181,7 @@ elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
build \
--rm \
-t rust-ci \
-f "host-$(uname -m)/$image/Dockerfile" \
-f "host-${machine}/$image/Dockerfile" \
-
else
echo Invalid image: $image
@ -201,7 +204,7 @@ else
else
continue
fi
echo "Note: the current host architecture is $(uname -m)"
echo "Note: the current host architecture is $machine"
done
exit 1

View File

@ -117,8 +117,7 @@ fn baz() {}
In various cases, the default Rust style specifies to sort things. If not
otherwise specified, such sorting should be "version sorting", which ensures
that (for instance) `x8` comes before `x16` even though the character `1` comes
before the character `8`. (If not otherwise specified, version-sorting is
lexicographical.)
before the character `8`.
For the purposes of the Rust style, to compare two strings for version-sorting:
@ -132,12 +131,13 @@ For the purposes of the Rust style, to compare two strings for version-sorting:
these strings, treat the chunks as equal (moving on to the next chunk) but
remember which string had more leading zeroes.
- To compare two chunks if both are not numeric, compare them by Unicode
character lexicographically, except that `_` (underscore) sorts immediately
after ` ` (space) but before any other character. (This treats underscore as
a word separator, as commonly used in identifiers.)
- If the use of version sorting specifies further modifiers, such as sorting
non-lowercase before lowercase, apply those modifiers to the lexicographic
sort in this step.
character lexicographically, with two exceptions:
- `_` (underscore) sorts immediately after ` ` (space) but before any other
character. (This treats underscore as a word separator, as commonly used in
identifiers.)
- Unless otherwise specified, version-sorting should sort non-lowercase
characters (characters that can start an `UpperCamelCase` identifier)
before lowercase characters.
- If the comparison reaches the end of the string and considers each pair of
chunks equal:
- If one of the numeric comparisons noted the earliest point at which one
@ -157,7 +157,17 @@ leading zeroes.
As an example, version-sorting will sort the following strings in the order
given:
- `_ZYWX`
- `_ZYXW`
- `_abcd`
- `A2`
- `ABCD`
- `Z_YXW`
- `ZY_XW`
- `ZY_XW`
- `ZYXW`
- `ZYXW_`
- `a1`
- `abcd`
- `u_zzz`
- `u8`
- `u16`
@ -190,11 +200,7 @@ given:
- `x86_64`
- `x86_128`
- `x87`
- `Z_YWX`
- `ZY_WX`
- `ZYW_X`
- `ZYWX`
- `ZYWX_`
- `zyxw`
### [Module-level items](items.md)

View File

@ -489,10 +489,8 @@ foo::{
A *group* of imports is a set of imports on the same or sequential lines. One or
more blank lines or other items (e.g., a function) separate groups of imports.
Within a group of imports, imports must be version-sorted, except that
non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters. Groups of imports must
not be merged or re-ordered.
Within a group of imports, imports must be version-sorted. Groups of imports
must not be merged or re-ordered.
E.g., input:
@ -520,9 +518,7 @@ re-ordering.
### Ordering list import
Names in a list import must be version-sorted, except that:
- `self` and `super` always come first if present,
- non-lowercase characters (characters that can start an `UpperCamelCase`
identifier) must be sorted before lowercase characters, and
- `self` and `super` always come first if present, and
- groups and glob imports always come last if present.
This applies recursively. For example, `a::*` comes before `b::a` but `a::b`

View File

@ -27,4 +27,16 @@ fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'
//~^ ERROR hidden type for
}
fn no_params_yet(_: impl Sized, y: &()) -> impl Sized {
//~^ HELP add a `use<...>` bound
y
//~^ ERROR hidden type for
}
fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized {
//~^ HELP add a `use<...>` bound
y
//~^ ERROR hidden type for
}
fn main() {}

View File

@ -62,6 +62,48 @@ help: add a `use<...>` bound to explicitly capture `'a`
LL | fn missing<'a, 'captured, 'not_captured, Captured>(x: &'a ()) -> impl Captures<'captured> + use<'captured, 'a, Captured> {
| ++++++++++++++++++++++++++++++
error: aborting due to 4 previous errors
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/hidden-type-suggestion.rs:32:5
|
LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized {
| --- ---------- opaque type defined here
| |
| hidden type `&()` captures the anonymous lifetime defined here
LL |
LL | y
| ^
|
note: you could use a `use<...>` bound to explicitly capture `'_`, but argument-position `impl Trait`s are not nameable
--> $DIR/hidden-type-suggestion.rs:30:21
|
LL | fn no_params_yet(_: impl Sized, y: &()) -> impl Sized {
| ^^^^^^^^^^
help: add a `use<...>` bound to explicitly capture `'_` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
|
LL | fn no_params_yet<T: Sized>(_: T, y: &()) -> impl Sized + use<'_, T> {
| ++++++++++ ~ ++++++++++++
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> $DIR/hidden-type-suggestion.rs:38:5
|
LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized {
| -- ---------- opaque type defined here
| |
| hidden type `&'a ()` captures the lifetime `'a` as defined here
LL |
LL | y
| ^
|
note: you could use a `use<...>` bound to explicitly capture `'a`, but argument-position `impl Trait`s are not nameable
--> $DIR/hidden-type-suggestion.rs:36:29
|
LL | fn yes_params_yet<'a, T>(_: impl Sized, y: &'a ()) -> impl Sized {
| ^^^^^^^^^^
help: add a `use<...>` bound to explicitly capture `'a` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate
|
LL | fn yes_params_yet<'a, T, U: Sized>(_: U, y: &'a ()) -> impl Sized + use<'a, T, U> {
| ++++++++++ ~ +++++++++++++++
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,6 +1,6 @@
//@ run-pass
#![allow(dead_code, non_camel_case_types, non_upper_case_globals)]
#![allow(dead_code, non_camel_case_types, non_upper_case_globals, unused_variables)]
#![feature(macro_metavar_expr_concat)]
macro_rules! create_things {
@ -37,13 +37,58 @@ macro_rules! without_dollar_sign_is_an_ident {
};
}
macro_rules! literals {
($ident:ident) => {{
let ${concat(_a, "_b")}: () = ();
let ${concat("_b", _a)}: () = ();
macro_rules! combinations {
($ident:ident, $literal:literal, $tt_ident:tt, $tt_literal:tt) => {{
// tt ident
let ${concat($tt_ident, b)} = ();
let ${concat($tt_ident, _b)} = ();
let ${concat($tt_ident, "b")} = ();
let ${concat($tt_ident, $tt_ident)} = ();
let ${concat($tt_ident, $tt_literal)} = ();
let ${concat($tt_ident, $ident)} = ();
let ${concat($tt_ident, $literal)} = ();
// tt literal
let ${concat($tt_literal, b)} = ();
let ${concat($tt_literal, _b)} = ();
let ${concat($tt_literal, "b")} = ();
let ${concat($tt_literal, $tt_ident)} = ();
let ${concat($tt_literal, $tt_literal)} = ();
let ${concat($tt_literal, $ident)} = ();
let ${concat($tt_literal, $literal)} = ();
let ${concat($ident, "_b")}: () = ();
let ${concat("_b", $ident)}: () = ();
// ident (adhoc)
let ${concat(_b, b)} = ();
let ${concat(_b, _b)} = ();
let ${concat(_b, "b")} = ();
let ${concat(_b, $tt_ident)} = ();
let ${concat(_b, $tt_literal)} = ();
let ${concat(_b, $ident)} = ();
let ${concat(_b, $literal)} = ();
// ident (param)
let ${concat($ident, b)} = ();
let ${concat($ident, _b)} = ();
let ${concat($ident, "b")} = ();
let ${concat($ident, $tt_ident)} = ();
let ${concat($ident, $tt_literal)} = ();
let ${concat($ident, $ident)} = ();
let ${concat($ident, $literal)} = ();
// literal (adhoc)
let ${concat("a", b)} = ();
let ${concat("a", _b)} = ();
let ${concat("a", "b")} = ();
let ${concat("a", $tt_ident)} = ();
let ${concat("a", $tt_literal)} = ();
let ${concat("a", $ident)} = ();
let ${concat("a", $literal)} = ();
// literal (param)
let ${concat($literal, b)} = ();
let ${concat($literal, _b)} = ();
let ${concat($literal, "b")} = ();
let ${concat($literal, $tt_ident)} = ();
let ${concat($literal, $tt_literal)} = ();
let ${concat($literal, $ident)} = ();
let ${concat($literal, $literal)} = ();
}};
}
@ -66,5 +111,5 @@ fn main() {
assert_eq!(VARident, 1);
assert_eq!(VAR_123, 2);
literals!(_hello);
combinations!(_hello, "a", b, "b");
}

View File

@ -20,7 +20,7 @@ macro_rules! wrong_concat_declarations {
//~^ ERROR `concat` must have at least two elements
${concat($ex, aaaa)}
//~^ ERROR `${concat(..)}` currently only accepts identifiers
//~^ ERROR metavariables of `${concat(..)}` must be of type
${concat($ex, aaaa 123)}
//~^ ERROR expected comma
@ -98,6 +98,39 @@ macro_rules! unsupported_literals {
}};
}
macro_rules! bad_literal_string {
($literal:literal) => {
const ${concat(_foo, $literal)}: () = ();
//~^ ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
//~| ERROR `${concat(..)}` is not generating a valid identifier
}
}
macro_rules! bad_literal_non_string {
($literal:literal) => {
const ${concat(_foo, $literal)}: () = ();
//~^ ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
}
}
macro_rules! bad_tt_literal {
($tt:tt) => {
const ${concat(_foo, $tt)}: () = ();
//~^ ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
//~| ERROR metavariables of `${concat(..)}` must be of type
}
}
fn main() {
wrong_concat_declarations!(1);
@ -113,4 +146,23 @@ fn main() {
unsupported_literals!(_abc);
empty!();
bad_literal_string!("\u{00BD}");
bad_literal_string!("\x41");
bad_literal_string!("🤷");
bad_literal_string!("d[-_-]b");
bad_literal_string!("-1");
bad_literal_string!("1.0");
bad_literal_string!("'1'");
bad_literal_non_string!(1);
bad_literal_non_string!(-1);
bad_literal_non_string!(1.0);
bad_literal_non_string!('1');
bad_literal_non_string!(false);
bad_tt_literal!(1);
bad_tt_literal!(1.0);
bad_tt_literal!('1');
}

View File

@ -64,11 +64,13 @@ error: expected identifier or string literal
LL | let ${concat($ident, 1)}: () = ();
| ^
error: `${concat(..)}` currently only accepts identifiers or meta-variables as parameters
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:22:19
|
LL | ${concat($ex, aaaa)}
| ^^
|
= note: currently only string literals are supported
error: variable `foo` is not recognized in meta-variable expression
--> $DIR/syntax-errors.rs:35:30
@ -131,5 +133,152 @@ LL | empty!();
|
= note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 18 previous errors
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("\u{00BD}");
| ------------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("\x41");
| --------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("🤷");
| ------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("d[-_-]b");
| ------------------------------ in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("-1");
| ------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("1.0");
| -------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `${concat(..)}` is not generating a valid identifier
--> $DIR/syntax-errors.rs:103:16
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | bad_literal_string!("'1'");
| -------------------------- in this macro invocation
|
= note: this error originates in the macro `bad_literal_string` (in Nightly builds, run with -Z macro-backtrace for more info)
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:116:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
|
= note: currently only string literals are supported
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:116:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:116:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:116:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:116:31
|
LL | const ${concat(_foo, $literal)}: () = ();
| ^^^^^^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:127:31
|
LL | const ${concat(_foo, $tt)}: () = ();
| ^^
|
= note: currently only string literals are supported
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:127:31
|
LL | const ${concat(_foo, $tt)}: () = ();
| ^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
--> $DIR/syntax-errors.rs:127:31
|
LL | const ${concat(_foo, $tt)}: () = ();
| ^^
|
= note: currently only string literals are supported
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 33 previous errors

View File

@ -3,12 +3,17 @@
#![feature(macro_metavar_expr_concat)]
macro_rules! turn_to_page {
($ident:ident) => {
($ident:ident, $literal:literal, $tt:tt) => {
const ${concat("", $ident)}: i32 = 394;
const ${concat("", $literal)}: i32 = 394;
const ${concat("", $tt)}: i32 = 394;
};
}
fn main() {
turn_to_page!(P);
assert_eq!(P, 394);
turn_to_page!(P1, "Ṕ2", );
assert_eq!(, 394);
assert_eq!(P1, 394);
assert_eq!(2, 394);
}