Auto merge of #126878 - matthiaskrgr:rollup-oufemqp, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #126230 (tidy: skip submodules if not present for non-CI environments) - #126612 (Update outdated README in build-manifest.) - #126616 (less bootstrap warnings) - #126663 (remove `GIT_DIR` handling in pre-push hook) - #126830 (make unsized_fn_params an internal feature) - #126833 (don't ICE when encountering an extern type field during validation) - #126837 (delegation: Do not crash on qpaths without a trait) - #126851 (Rework pattern and expression nonterminal kinds.) - #126862 (Add needs-symlink directive to compiletest) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
bcf94dec5b
43 changed files with 344 additions and 212 deletions
|
@ -5678,6 +5678,7 @@ dependencies = [
|
|||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"cargo_metadata 0.15.4",
|
||||
"fluent-syntax",
|
||||
"ignore",
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
pub use BinOpToken::*;
|
||||
pub use LitKind::*;
|
||||
pub use Nonterminal::*;
|
||||
pub use NtExprKind::*;
|
||||
pub use NtPatKind::*;
|
||||
pub use TokenKind::*;
|
||||
|
||||
use crate::ast;
|
||||
|
@ -871,6 +873,27 @@ impl PartialEq<TokenKind> for Token {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
||||
pub enum NtPatKind {
|
||||
// Matches or-patterns. Was written using `pat` in edition 2021 or later.
|
||||
PatWithOr,
|
||||
// Doesn't match or-patterns.
|
||||
// - `inferred`: was written using `pat` in edition 2015 or 2018.
|
||||
// - `!inferred`: was written using `pat_param`.
|
||||
PatParam { inferred: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable)]
|
||||
pub enum NtExprKind {
|
||||
// Matches expressions using the post-edition 2024. Was written using
|
||||
// `expr` in edition 2024 or later.
|
||||
Expr,
|
||||
// Matches expressions using the pre-edition 2024 rules.
|
||||
// - `inferred`: was written using `expr` in edition 2021 or earlier.
|
||||
// - `!inferred`: was written using `expr_2021`.
|
||||
Expr2021 { inferred: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable)]
|
||||
/// For interpolation during macro expansion.
|
||||
pub enum Nonterminal {
|
||||
|
@ -892,19 +915,8 @@ pub enum NonterminalKind {
|
|||
Item,
|
||||
Block,
|
||||
Stmt,
|
||||
PatParam {
|
||||
/// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
|
||||
/// edition of the span. This is used for diagnostics.
|
||||
inferred: bool,
|
||||
},
|
||||
PatWithOr,
|
||||
Expr,
|
||||
/// Matches an expression using the rules from edition 2021 and earlier.
|
||||
Expr2021 {
|
||||
/// Keep track of whether the user used `:expr` or `:expr_2021` and we inferred it from the
|
||||
/// edition of the span. This is used for diagnostics AND feature gating.
|
||||
inferred: bool,
|
||||
},
|
||||
Pat(NtPatKind),
|
||||
Expr(NtExprKind),
|
||||
Ty,
|
||||
Ident,
|
||||
Lifetime,
|
||||
|
@ -926,20 +938,22 @@ impl NonterminalKind {
|
|||
sym::item => NonterminalKind::Item,
|
||||
sym::block => NonterminalKind::Block,
|
||||
sym::stmt => NonterminalKind::Stmt,
|
||||
sym::pat => match edition() {
|
||||
Edition::Edition2015 | Edition::Edition2018 => {
|
||||
NonterminalKind::PatParam { inferred: true }
|
||||
sym::pat => {
|
||||
if edition().at_least_rust_2021() {
|
||||
NonterminalKind::Pat(PatWithOr)
|
||||
} else {
|
||||
NonterminalKind::Pat(PatParam { inferred: true })
|
||||
}
|
||||
Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
|
||||
},
|
||||
sym::pat_param => NonterminalKind::PatParam { inferred: false },
|
||||
sym::expr => match edition() {
|
||||
Edition::Edition2015 | Edition::Edition2018 | Edition::Edition2021 => {
|
||||
NonterminalKind::Expr2021 { inferred: true }
|
||||
}
|
||||
sym::pat_param => NonterminalKind::Pat(PatParam { inferred: false }),
|
||||
sym::expr => {
|
||||
if edition().at_least_rust_2024() {
|
||||
NonterminalKind::Expr(Expr)
|
||||
} else {
|
||||
NonterminalKind::Expr(Expr2021 { inferred: true })
|
||||
}
|
||||
Edition::Edition2024 => NonterminalKind::Expr,
|
||||
},
|
||||
sym::expr_2021 => NonterminalKind::Expr2021 { inferred: false },
|
||||
}
|
||||
sym::expr_2021 => NonterminalKind::Expr(Expr2021 { inferred: false }),
|
||||
sym::ty => NonterminalKind::Ty,
|
||||
sym::ident => NonterminalKind::Ident,
|
||||
sym::lifetime => NonterminalKind::Lifetime,
|
||||
|
@ -951,15 +965,16 @@ impl NonterminalKind {
|
|||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn symbol(self) -> Symbol {
|
||||
match self {
|
||||
NonterminalKind::Item => sym::item,
|
||||
NonterminalKind::Block => sym::block,
|
||||
NonterminalKind::Stmt => sym::stmt,
|
||||
NonterminalKind::PatParam { inferred: false } => sym::pat_param,
|
||||
NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
|
||||
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: true } => sym::expr,
|
||||
NonterminalKind::Expr2021 { inferred: false } => sym::expr_2021,
|
||||
NonterminalKind::Pat(PatParam { inferred: true } | PatWithOr) => sym::pat,
|
||||
NonterminalKind::Pat(PatParam { inferred: false }) => sym::pat_param,
|
||||
NonterminalKind::Expr(Expr2021 { inferred: true } | Expr) => sym::expr,
|
||||
NonterminalKind::Expr(Expr2021 { inferred: false }) => sym::expr_2021,
|
||||
NonterminalKind::Ty => sym::ty,
|
||||
NonterminalKind::Ident => sym::ident,
|
||||
NonterminalKind::Lifetime => sym::lifetime,
|
||||
|
|
|
@ -89,6 +89,8 @@ const_eval_exact_div_has_remainder =
|
|||
|
||||
const_eval_extern_static =
|
||||
cannot access extern static ({$did})
|
||||
const_eval_extern_type_field = `extern type` field does not have a known offset
|
||||
|
||||
const_eval_fn_ptr_call =
|
||||
function pointers need an RFC before allowed to be called in {const_eval_const_context}s
|
||||
const_eval_for_loop_into_iter_non_const =
|
||||
|
|
|
@ -386,33 +386,8 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
|
|||
CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
|
||||
);
|
||||
let res = ecx.load_mir(cid.instance.def, cid.promoted);
|
||||
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| {
|
||||
let (error, backtrace) = error.into_parts();
|
||||
backtrace.print_backtrace();
|
||||
|
||||
let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) {
|
||||
("static", String::new())
|
||||
} else {
|
||||
// If the current item has generics, we'd like to enrich the message with the
|
||||
// instance and its args: to show the actual compile-time values, in addition to
|
||||
// the expression, leading to the const eval error.
|
||||
let instance = &cid.instance;
|
||||
if !instance.args.is_empty() {
|
||||
let instance = with_no_trimmed_paths!(instance.to_string());
|
||||
("const_with_path", instance)
|
||||
} else {
|
||||
("const", String::new())
|
||||
}
|
||||
};
|
||||
|
||||
super::report(
|
||||
*ecx.tcx,
|
||||
error,
|
||||
DUMMY_SP,
|
||||
|| super::get_span_and_frames(ecx.tcx, ecx.stack()),
|
||||
|span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames },
|
||||
)
|
||||
})
|
||||
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
|
||||
.map_err(|error| report_eval_error(&ecx, cid, error))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -438,23 +413,60 @@ fn const_validate_mplace<'tcx>(
|
|||
ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
|
||||
// Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted
|
||||
// error about the validation failure.
|
||||
.map_err(|error| report_validation_error(&ecx, error, alloc_id))?;
|
||||
.map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?;
|
||||
inner = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn report_validation_error<'tcx>(
|
||||
#[inline(never)]
|
||||
fn report_eval_error<'tcx>(
|
||||
ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
|
||||
cid: GlobalId<'tcx>,
|
||||
error: InterpErrorInfo<'tcx>,
|
||||
alloc_id: AllocId,
|
||||
) -> ErrorHandled {
|
||||
let (error, backtrace) = error.into_parts();
|
||||
backtrace.print_backtrace();
|
||||
|
||||
let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {});
|
||||
let (kind, instance) = if ecx.tcx.is_static(cid.instance.def_id()) {
|
||||
("static", String::new())
|
||||
} else {
|
||||
// If the current item has generics, we'd like to enrich the message with the
|
||||
// instance and its args: to show the actual compile-time values, in addition to
|
||||
// the expression, leading to the const eval error.
|
||||
let instance = &cid.instance;
|
||||
if !instance.args.is_empty() {
|
||||
let instance = with_no_trimmed_paths!(instance.to_string());
|
||||
("const_with_path", instance)
|
||||
} else {
|
||||
("const", String::new())
|
||||
}
|
||||
};
|
||||
|
||||
super::report(
|
||||
*ecx.tcx,
|
||||
error,
|
||||
DUMMY_SP,
|
||||
|| super::get_span_and_frames(ecx.tcx, ecx.stack()),
|
||||
|span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames },
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn report_validation_error<'tcx>(
|
||||
ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
|
||||
cid: GlobalId<'tcx>,
|
||||
error: InterpErrorInfo<'tcx>,
|
||||
alloc_id: AllocId,
|
||||
) -> ErrorHandled {
|
||||
if !matches!(error.kind(), InterpError::UndefinedBehavior(_)) {
|
||||
// Some other error happened during validation, e.g. an unsupported operation.
|
||||
return report_eval_error(ecx, cid, error);
|
||||
}
|
||||
|
||||
let (error, backtrace) = error.into_parts();
|
||||
backtrace.print_backtrace();
|
||||
|
||||
let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
|
||||
let (size, align, _) = ecx.get_alloc_info(alloc_id);
|
||||
|
@ -465,6 +477,6 @@ fn report_validation_error<'tcx>(
|
|||
error,
|
||||
DUMMY_SP,
|
||||
|| crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()),
|
||||
move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes },
|
||||
move |span, frames| errors::ValidationFailure { span, ub_note: (), frames, raw_bytes },
|
||||
)
|
||||
}
|
||||
|
|
|
@ -425,7 +425,7 @@ pub struct ValidationFailure {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[note(const_eval_validation_failure_note)]
|
||||
pub ub_note: Option<()>,
|
||||
pub ub_note: (),
|
||||
#[subdiagnostic]
|
||||
pub frames: Vec<FrameNote>,
|
||||
#[subdiagnostic]
|
||||
|
@ -825,6 +825,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
|||
use crate::fluent_generated::*;
|
||||
match self {
|
||||
UnsupportedOpInfo::Unsupported(s) => s.clone().into(),
|
||||
UnsupportedOpInfo::ExternTypeField => const_eval_extern_type_field,
|
||||
UnsupportedOpInfo::UnsizedLocal => const_eval_unsized_local,
|
||||
UnsupportedOpInfo::OverwritePartialPointer(_) => const_eval_partial_pointer_overwrite,
|
||||
UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
|
||||
|
@ -845,7 +846,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
|||
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
|
||||
// be further processed by validity checking which then turns it into something nice to
|
||||
// print. So it's not worth the effort of having diagnostics that can print the `info`.
|
||||
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
|
||||
UnsizedLocal
|
||||
| UnsupportedOpInfo::ExternTypeField
|
||||
| Unsupported(_)
|
||||
| ReadPointerAsInt(_) => {}
|
||||
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
||||
diag.arg("ptr", ptr);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use rustc_target::abi::{self, VariantIdx};
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{
|
||||
throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
||||
throw_ub, throw_unsup, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
||||
Provenance, Scalar,
|
||||
};
|
||||
|
||||
|
@ -186,8 +186,8 @@ where
|
|||
(base_meta, offset)
|
||||
}
|
||||
None => {
|
||||
// We don't know the alignment of this field, so we cannot adjust.
|
||||
throw_unsup_format!("`extern type` does not have a known offset")
|
||||
// We cannot know the alignment of this field, so we cannot adjust.
|
||||
throw_unsup!(ExternTypeField)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//! to be const-safe.
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::hash::Hash;
|
||||
use std::num::NonZero;
|
||||
|
||||
use either::{Left, Right};
|
||||
|
@ -17,7 +18,8 @@ use rustc_hir as hir;
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::interpret::{
|
||||
ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
|
||||
ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
|
||||
UnsupportedOpInfo, ValidationErrorInfo,
|
||||
ValidationErrorKind::{self, *},
|
||||
};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
|
@ -26,8 +28,6 @@ use rustc_target::abi::{
|
|||
Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
|
||||
};
|
||||
|
||||
use std::hash::Hash;
|
||||
|
||||
use super::{
|
||||
err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, AllocKind, CheckInAllocMsg,
|
||||
GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
|
||||
|
@ -1028,7 +1028,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
Err(err)
|
||||
if matches!(
|
||||
err.kind(),
|
||||
err_ub!(ValidationError { .. }) | InterpError::InvalidProgram(_)
|
||||
err_ub!(ValidationError { .. })
|
||||
| InterpError::InvalidProgram(_)
|
||||
| InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField)
|
||||
) =>
|
||||
{
|
||||
Err(err)
|
||||
|
|
|
@ -61,6 +61,9 @@ expand_feature_removed =
|
|||
expand_glob_delegation_outside_impls =
|
||||
glob delegation is only supported in impls
|
||||
|
||||
expand_glob_delegation_traitless_qpath =
|
||||
qualified path without a trait in glob delegation
|
||||
|
||||
expand_helper_attribute_name_invalid =
|
||||
`{$name}` cannot be a name of derive helper attribute
|
||||
|
||||
|
|
|
@ -449,6 +449,13 @@ pub(crate) struct GlobDelegationOutsideImpls {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_glob_delegation_traitless_qpath)]
|
||||
pub(crate) struct GlobDelegationTraitlessQpath {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// This used to be the `proc_macro_back_compat` lint (#83125). It was later
|
||||
// turned into a hard error.
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::base::*;
|
||||
use crate::config::StripUnconfigured;
|
||||
use crate::errors::{
|
||||
EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached,
|
||||
RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
|
||||
EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse,
|
||||
RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue,
|
||||
WrongFragmentKind,
|
||||
};
|
||||
use crate::mbe::diagnostics::annotate_err_with_kind;
|
||||
use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
|
||||
|
@ -1989,6 +1990,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
}
|
||||
None if let Some((deleg, item)) = node.delegation() => {
|
||||
let Some(suffixes) = &deleg.suffixes else {
|
||||
let traitless_qself =
|
||||
matches!(&deleg.qself, Some(qself) if qself.position == 0);
|
||||
let item = match node.to_annotatable() {
|
||||
Annotatable::ImplItem(item) => item,
|
||||
ann @ (Annotatable::Item(_)
|
||||
|
@ -2000,6 +2003,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if traitless_qself {
|
||||
let span = item.span;
|
||||
self.cx.dcx().emit_err(GlobDelegationTraitlessQpath { span });
|
||||
return Default::default();
|
||||
}
|
||||
return self.collect_glob_delegation(item, Node::KIND).make_ast::<Node>();
|
||||
};
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ use crate::mbe::transcribe::transcribe;
|
|||
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind, TokenKind::*};
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, NonterminalKind, NtPatKind::*, Token, TokenKind, TokenKind::*,
|
||||
};
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||
use rustc_ast_pretty::pprust;
|
||||
|
@ -1145,14 +1147,17 @@ fn check_matcher_core<'tt>(
|
|||
// Macros defined in the current crate have a real node id,
|
||||
// whereas macros from an external crate have a dummy id.
|
||||
if def.id != DUMMY_NODE_ID
|
||||
&& matches!(kind, NonterminalKind::PatParam { inferred: true })
|
||||
&& matches!(next_token, TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or))
|
||||
&& matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
|
||||
&& matches!(
|
||||
next_token,
|
||||
TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)
|
||||
)
|
||||
{
|
||||
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::PatParam { inferred: false }),
|
||||
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||
));
|
||||
sess.psess.buffer_lint(
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||
|
@ -1185,14 +1190,14 @@ fn check_matcher_core<'tt>(
|
|||
);
|
||||
err.span_label(sp, format!("not allowed after `{kind}` fragments"));
|
||||
|
||||
if kind == NonterminalKind::PatWithOr
|
||||
if kind == NonterminalKind::Pat(PatWithOr)
|
||||
&& sess.psess.edition.at_least_rust_2021()
|
||||
&& next_token.is_token(&BinOp(token::BinOpToken::Or))
|
||||
{
|
||||
let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
|
||||
span,
|
||||
name,
|
||||
Some(NonterminalKind::PatParam { inferred: false }),
|
||||
Some(NonterminalKind::Pat(PatParam { inferred: false })),
|
||||
));
|
||||
err.span_suggestion(
|
||||
span,
|
||||
|
@ -1292,9 +1297,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||
// maintain
|
||||
IsInFollow::Yes
|
||||
}
|
||||
NonterminalKind::Stmt
|
||||
| NonterminalKind::Expr
|
||||
| NonterminalKind::Expr2021 { inferred: _ } => {
|
||||
NonterminalKind::Stmt | NonterminalKind::Expr(_) => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
|
@ -1304,7 +1307,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
NonterminalKind::PatParam { .. } => {
|
||||
NonterminalKind::Pat(PatParam { .. }) => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
|
@ -1317,7 +1320,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
|
|||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
}
|
||||
NonterminalKind::PatWithOr => {
|
||||
NonterminalKind::Pat(PatWithOr) => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors;
|
|||
use crate::mbe::macro_parser::count_metavar_decls;
|
||||
use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree};
|
||||
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Token};
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, NtExprKind::*, Token};
|
||||
use rustc_ast::{tokenstream, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_feature::Features;
|
||||
|
@ -85,36 +85,31 @@ pub(super) fn parse(
|
|||
span.edition()
|
||||
}
|
||||
};
|
||||
let kind =
|
||||
token::NonterminalKind::from_symbol(fragment.name, edition)
|
||||
.unwrap_or_else(|| {
|
||||
let help = match fragment.name {
|
||||
sym::expr_2021 => {
|
||||
format!(
|
||||
"fragment specifier `expr_2021` \
|
||||
requires Rust 2021 or later\n\
|
||||
{VALID_FRAGMENT_NAMES_MSG}"
|
||||
)
|
||||
}
|
||||
_ if edition().at_least_rust_2021()
|
||||
&& features
|
||||
.expr_fragment_specifier_2024 =>
|
||||
{
|
||||
VALID_FRAGMENT_NAMES_MSG_2021.into()
|
||||
}
|
||||
_ => VALID_FRAGMENT_NAMES_MSG.into(),
|
||||
};
|
||||
sess.dcx().emit_err(
|
||||
errors::InvalidFragmentSpecifier {
|
||||
span,
|
||||
fragment,
|
||||
help,
|
||||
},
|
||||
);
|
||||
token::NonterminalKind::Ident
|
||||
let kind = NonterminalKind::from_symbol(fragment.name, edition)
|
||||
.unwrap_or_else(|| {
|
||||
let help = match fragment.name {
|
||||
sym::expr_2021 => {
|
||||
format!(
|
||||
"fragment specifier `expr_2021` \
|
||||
requires Rust 2021 or later\n\
|
||||
{VALID_FRAGMENT_NAMES_MSG}"
|
||||
)
|
||||
}
|
||||
_ if edition().at_least_rust_2021()
|
||||
&& features.expr_fragment_specifier_2024 =>
|
||||
{
|
||||
VALID_FRAGMENT_NAMES_MSG_2021.into()
|
||||
}
|
||||
_ => VALID_FRAGMENT_NAMES_MSG.into(),
|
||||
};
|
||||
sess.dcx().emit_err(errors::InvalidFragmentSpecifier {
|
||||
span,
|
||||
fragment,
|
||||
help,
|
||||
});
|
||||
if kind
|
||||
== (token::NonterminalKind::Expr2021 { inferred: false })
|
||||
NonterminalKind::Ident
|
||||
});
|
||||
if kind == NonterminalKind::Expr(Expr2021 { inferred: false })
|
||||
&& !features.expr_fragment_specifier_2024
|
||||
{
|
||||
rustc_session::parse::feature_err(
|
||||
|
|
|
@ -629,7 +629,7 @@ declare_features! (
|
|||
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
|
||||
(unstable, unsafe_extern_blocks, "1.80.0", Some(123743)),
|
||||
/// Allows unsized fn parameters.
|
||||
(unstable, unsized_fn_params, "1.49.0", Some(48055)),
|
||||
(internal, unsized_fn_params, "1.49.0", Some(48055)),
|
||||
/// Allows unsized rvalues at arguments and parameters.
|
||||
(incomplete, unsized_locals, "1.30.0", Some(48055)),
|
||||
/// Allows unsized tuple coercion.
|
||||
|
|
|
@ -520,6 +520,8 @@ pub enum UnsupportedOpInfo {
|
|||
Unsupported(String),
|
||||
/// Unsized local variables.
|
||||
UnsizedLocal,
|
||||
/// Extern type field with an indeterminate offset.
|
||||
ExternTypeField,
|
||||
//
|
||||
// The variants below are only reachable from CTFE/const prop, miri will never emit them.
|
||||
//
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, Nonterminal::*, NonterminalKind, NtExprKind::*, NtPatKind::*, Token,
|
||||
};
|
||||
use rustc_ast::HasTokens;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
@ -36,14 +38,14 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
match kind {
|
||||
NonterminalKind::Expr2021 { inferred: _ } => {
|
||||
NonterminalKind::Expr(Expr2021 { .. }) => {
|
||||
token.can_begin_expr()
|
||||
// This exception is here for backwards compatibility.
|
||||
&& !token.is_keyword(kw::Let)
|
||||
// This exception is here for backwards compatibility.
|
||||
&& !token.is_keyword(kw::Const)
|
||||
}
|
||||
NonterminalKind::Expr => {
|
||||
NonterminalKind::Expr(Expr) => {
|
||||
token.can_begin_expr()
|
||||
// This exception is here for backwards compatibility.
|
||||
&& !token.is_keyword(kw::Let)
|
||||
|
@ -74,7 +76,7 @@ impl<'a> Parser<'a> {
|
|||
token::Interpolated(nt) => may_be_ident(nt),
|
||||
_ => false,
|
||||
},
|
||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
|
||||
NonterminalKind::Pat(pat_kind) => match &token.kind {
|
||||
// box, ref, mut, and other identifiers (can stricten)
|
||||
token::Ident(..) | token::NtIdent(..) |
|
||||
token::OpenDelim(Delimiter::Parenthesis) | // tuple pattern
|
||||
|
@ -89,7 +91,7 @@ impl<'a> Parser<'a> {
|
|||
token::Lt | // path (UFCS constant)
|
||||
token::BinOp(token::Shl) => true, // path (double UFCS)
|
||||
// leading vert `|` or-pattern
|
||||
token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
|
||||
token::BinOp(token::Or) => matches!(pat_kind, PatWithOr),
|
||||
token::Interpolated(nt) => may_be_ident(nt),
|
||||
_ => false,
|
||||
},
|
||||
|
@ -135,31 +137,25 @@ impl<'a> Parser<'a> {
|
|||
.create_err(UnexpectedNonterminal::Statement(self.token.span)));
|
||||
}
|
||||
},
|
||||
NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
|
||||
NtPat(self.collect_tokens_no_attrs(|this| match kind {
|
||||
NonterminalKind::PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||
NonterminalKind::PatWithOr => this.parse_pat_allow_top_alt(
|
||||
NonterminalKind::Pat(pat_kind) => {
|
||||
NtPat(self.collect_tokens_no_attrs(|this| match pat_kind {
|
||||
PatParam { .. } => this.parse_pat_no_top_alt(None, None),
|
||||
PatWithOr => this.parse_pat_allow_top_alt(
|
||||
None,
|
||||
RecoverComma::No,
|
||||
RecoverColon::No,
|
||||
CommaRecoveryMode::EitherTupleOrPipe,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
})?)
|
||||
}
|
||||
|
||||
NonterminalKind::Expr | NonterminalKind::Expr2021 { inferred: _ } => {
|
||||
NtExpr(self.parse_expr_force_collect()?)
|
||||
}
|
||||
NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?),
|
||||
NonterminalKind::Literal => {
|
||||
// The `:literal` matcher does not support attributes
|
||||
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
|
||||
}
|
||||
|
||||
NonterminalKind::Ty => {
|
||||
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
|
||||
}
|
||||
|
||||
// this could be handled like a token, since it is one
|
||||
NonterminalKind::Ident => {
|
||||
return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
|
||||
|
|
|
@ -1290,15 +1290,21 @@ fn needs_codegen_config(run: &RunConfig<'_>) -> bool {
|
|||
pub(crate) const CODEGEN_BACKEND_PREFIX: &str = "rustc_codegen_";
|
||||
|
||||
fn is_codegen_cfg_needed(path: &TaskPath, run: &RunConfig<'_>) -> bool {
|
||||
if path.path.to_str().unwrap().contains(CODEGEN_BACKEND_PREFIX) {
|
||||
let path = path.path.to_str().unwrap();
|
||||
|
||||
let is_explicitly_called = |p| -> bool { run.builder.paths.contains(p) };
|
||||
let should_enforce = run.builder.kind == Kind::Dist || run.builder.kind == Kind::Install;
|
||||
|
||||
if path.contains(CODEGEN_BACKEND_PREFIX) {
|
||||
let mut needs_codegen_backend_config = true;
|
||||
for backend in run.builder.config.codegen_backends(run.target) {
|
||||
if path.path.to_str().unwrap().ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend))
|
||||
{
|
||||
if path.ends_with(&(CODEGEN_BACKEND_PREFIX.to_owned() + backend)) {
|
||||
needs_codegen_backend_config = false;
|
||||
}
|
||||
}
|
||||
if needs_codegen_backend_config {
|
||||
if (is_explicitly_called(&PathBuf::from(path)) || should_enforce)
|
||||
&& needs_codegen_backend_config
|
||||
{
|
||||
run.builder.info(
|
||||
"WARNING: no codegen-backends config matched the requested path to build a codegen backend. \
|
||||
HELP: add backend to codegen-backends in config.toml.",
|
||||
|
|
|
@ -1018,7 +1018,7 @@ impl Step for PlainSourceTarball {
|
|||
// perhaps it should be removed in favor of making `dist` perform the `vendor` step?
|
||||
|
||||
// Ensure we have all submodules from src and other directories checked out.
|
||||
for submodule in builder.get_all_submodules() {
|
||||
for submodule in build_helper::util::parse_gitmodules(&builder.src) {
|
||||
builder.update_submodule(Path::new(submodule));
|
||||
}
|
||||
|
||||
|
|
|
@ -1048,8 +1048,6 @@ impl Step for Tidy {
|
|||
/// Once tidy passes, this step also runs `fmt --check` if tests are being run
|
||||
/// for the `dev` or `nightly` channels.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
builder.build.update_submodule(Path::new("src/tools/rustc-perf"));
|
||||
|
||||
let mut cmd = builder.tool_cmd(Tool::Tidy);
|
||||
cmd.arg(&builder.src);
|
||||
cmd.arg(&builder.initial_cargo);
|
||||
|
|
|
@ -4,13 +4,11 @@ use std::collections::BTreeSet;
|
|||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fmt::{Debug, Write};
|
||||
use std::fs::{self, File};
|
||||
use std::fs;
|
||||
use std::hash::Hash;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::core::build_steps::tool::{self, SourceType};
|
||||
|
@ -594,7 +592,7 @@ impl<'a> ShouldRun<'a> {
|
|||
///
|
||||
/// [`path`]: ShouldRun::path
|
||||
pub fn paths(mut self, paths: &[&str]) -> Self {
|
||||
let submodules_paths = self.builder.get_all_submodules();
|
||||
let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src);
|
||||
|
||||
self.paths.insert(PathSet::Set(
|
||||
paths
|
||||
|
@ -2243,28 +2241,6 @@ impl<'a> Builder<'a> {
|
|||
out
|
||||
}
|
||||
|
||||
/// Return paths of all submodules.
|
||||
pub fn get_all_submodules(&self) -> &[String] {
|
||||
static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
|
||||
|
||||
let init_submodules_paths = |src: &PathBuf| {
|
||||
let file = File::open(src.join(".gitmodules")).unwrap();
|
||||
|
||||
let mut submodules_paths = vec![];
|
||||
for line in BufReader::new(file).lines().map_while(Result::ok) {
|
||||
let line = line.trim();
|
||||
if line.starts_with("path") {
|
||||
let actual_path = line.split(' ').last().expect("Couldn't get value of path");
|
||||
submodules_paths.push(actual_path.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
submodules_paths
|
||||
};
|
||||
|
||||
SUBMODULES_PATHS.get_or_init(|| init_submodules_paths(&self.src))
|
||||
}
|
||||
|
||||
/// Ensure that a given step is built *only if it's supposed to be built by default*, returning
|
||||
/// its output. This will cache the step, so it's safe (and good!) to call this as often as
|
||||
/// needed to ensure that all dependencies are build.
|
||||
|
|
|
@ -135,7 +135,7 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
|
|||
if config.dry_run() {
|
||||
return Ok(());
|
||||
}
|
||||
let _ = fs::remove_dir(link);
|
||||
let _ = fs::remove_dir_all(link);
|
||||
return symlink_dir_inner(original, link);
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
set -Euo pipefail
|
||||
|
||||
# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
|
||||
unset GIT_DIR
|
||||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||||
|
||||
echo "Running pre-push script $ROOT_DIR/x test tidy"
|
||||
|
|
|
@ -4,7 +4,7 @@ This tool generates the manifests uploaded to static.rust-lang.org and used by r
|
|||
You can see a full list of all manifests at <https://static.rust-lang.org/manifests.txt>.
|
||||
This listing is updated by <https://github.com/rust-lang/generate-manifest-list> every 7 days.
|
||||
|
||||
This gets called by `promote-release` <https://github.com/rust-lang/promote-release> via `x.py dist hash-and-sign`.
|
||||
This gets called by `promote-release` <https://github.com/rust-lang/promote-release>. `promote-release` downloads a pre-built binary of `build-manifest` which is generated in the dist-x86_64-linux builder and uploaded to s3.
|
||||
|
||||
## Adding a new component
|
||||
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
/// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
|
||||
///
|
||||
|
@ -45,3 +49,27 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the submodule paths from the `.gitmodules` file in the given directory.
|
||||
pub fn parse_gitmodules(target_dir: &Path) -> &[String] {
|
||||
static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
|
||||
let gitmodules = target_dir.join(".gitmodules");
|
||||
assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
|
||||
|
||||
let init_submodules_paths = || {
|
||||
let file = File::open(gitmodules).unwrap();
|
||||
|
||||
let mut submodules_paths = vec![];
|
||||
for line in BufReader::new(file).lines().map_while(Result::ok) {
|
||||
let line = line.trim();
|
||||
if line.starts_with("path") {
|
||||
let actual_path = line.split(' ').last().expect("Couldn't get value of path");
|
||||
submodules_paths.push(actual_path.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
submodules_paths
|
||||
};
|
||||
|
||||
SUBMODULES_PATHS.get_or_init(|| init_submodules_paths())
|
||||
}
|
||||
|
|
|
@ -877,6 +877,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
|||
"needs-sanitizer-shadow-call-stack",
|
||||
"needs-sanitizer-support",
|
||||
"needs-sanitizer-thread",
|
||||
"needs-symlink",
|
||||
"needs-threads",
|
||||
"needs-unwind",
|
||||
"needs-wasmtime",
|
||||
|
|
|
@ -144,6 +144,11 @@ pub(super) fn handle_needs(
|
|||
condition: config.runner.as_ref().is_some_and(|r| r.contains("wasmtime")),
|
||||
ignore_reason: "ignored when wasmtime runner is not available",
|
||||
},
|
||||
Need {
|
||||
name: "needs-symlink",
|
||||
condition: cache.symlinks,
|
||||
ignore_reason: "ignored if symlinks are unavailable",
|
||||
},
|
||||
];
|
||||
|
||||
let (name, comment) = match ln.split_once([':', ' ']) {
|
||||
|
@ -209,6 +214,7 @@ pub(super) struct CachedNeedsConditions {
|
|||
xray: bool,
|
||||
rust_lld: bool,
|
||||
dlltool: bool,
|
||||
symlinks: bool,
|
||||
}
|
||||
|
||||
impl CachedNeedsConditions {
|
||||
|
@ -253,6 +259,7 @@ impl CachedNeedsConditions {
|
|||
.exists(),
|
||||
|
||||
dlltool: find_dlltool(&config),
|
||||
symlinks: has_symlinks(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,3 +286,22 @@ fn find_dlltool(config: &Config) -> bool {
|
|||
};
|
||||
dlltool_found
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn has_symlinks() -> bool {
|
||||
if std::env::var_os("CI").is_some() {
|
||||
return true;
|
||||
}
|
||||
let link = std::env::temp_dir().join("RUST_COMPILETEST_SYMLINK_CHECK");
|
||||
if std::os::windows::fs::symlink_file("DOES NOT EXIST", &link).is_ok() {
|
||||
std::fs::remove_file(&link).unwrap();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn has_symlinks() -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
@ -311,7 +311,9 @@ pub fn report_error<'tcx>(
|
|||
ResourceExhaustion(_) => "resource exhaustion",
|
||||
Unsupported(
|
||||
// We list only the ones that can actually happen.
|
||||
UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::UnsizedLocal,
|
||||
UnsupportedOpInfo::Unsupported(_)
|
||||
| UnsupportedOpInfo::UnsizedLocal
|
||||
| UnsupportedOpInfo::ExternTypeField,
|
||||
) => "unsupported operation",
|
||||
InvalidProgram(
|
||||
// We list only the ones that can actually happen.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: unsupported operation: `extern type` does not have a known offset
|
||||
error: unsupported operation: `extern type` field does not have a known offset
|
||||
--> $DIR/extern-type-field-offset.rs:LL:CC
|
||||
|
|
||||
LL | let _field = &x.a;
|
||||
| ^^^^ `extern type` does not have a known offset
|
||||
| ^^^^ `extern type` field does not have a known offset
|
||||
|
|
||||
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
|
||||
= note: BACKTRACE:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind};
|
||||
use rustc_ast::token::{Delimiter, NonterminalKind, NtExprKind::*, NtPatKind::*, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{ast, ptr};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, Recovery};
|
||||
|
@ -48,7 +48,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
|||
|
||||
parse_macro_arg!(
|
||||
Expr,
|
||||
NonterminalKind::Expr,
|
||||
NonterminalKind::Expr(Expr),
|
||||
|parser: &mut Parser<'b>| parser.parse_expr(),
|
||||
|x: ptr::P<ast::Expr>| Some(x)
|
||||
);
|
||||
|
@ -60,7 +60,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
|
|||
);
|
||||
parse_macro_arg!(
|
||||
Pat,
|
||||
NonterminalKind::PatParam { inferred: false },
|
||||
NonterminalKind::Pat(PatParam { inferred: false }),
|
||||
|parser: &mut Parser<'b>| parser.parse_pat_no_top_alt(None, None),
|
||||
|x: ptr::P<ast::Pat>| Some(x)
|
||||
);
|
||||
|
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||
autobins = false
|
||||
|
||||
[dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
cargo_metadata = "0.15"
|
||||
regex = "1"
|
||||
miropt-test-tools = { path = "../miropt-test-tools" }
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
//! Checks the licenses of third-party dependencies.
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use cargo_metadata::{Metadata, Package, PackageId};
|
||||
use std::collections::HashSet;
|
||||
use std::fs::read_dir;
|
||||
use std::path::Path;
|
||||
|
||||
/// These are licenses that are allowed for all crates, including the runtime,
|
||||
|
@ -514,7 +516,19 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
|
|||
pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
|
||||
let mut checked_runtime_licenses = false;
|
||||
|
||||
let submodules = build_helper::util::parse_gitmodules(root);
|
||||
for &(workspace, exceptions, permitted_deps) in WORKSPACES {
|
||||
// Skip if it's a submodule, not in a CI environment, and not initialized.
|
||||
//
|
||||
// This prevents enforcing developers to fetch submodules for tidy.
|
||||
if submodules.contains(&workspace.into())
|
||||
&& !CiEnv::is_ci()
|
||||
// If the directory is empty, we can consider it as an uninitialized submodule.
|
||||
&& read_dir(root.join(workspace)).unwrap().next().is_none()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if !root.join(workspace).join("Cargo.lock").exists() {
|
||||
tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
|
||||
continue;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Check for external package sources. Allow only vendorable packages.
|
||||
|
||||
use std::fs;
|
||||
use build_helper::ci::CiEnv;
|
||||
use std::fs::{self, read_dir};
|
||||
use std::path::Path;
|
||||
|
||||
/// List of allowed sources for packages.
|
||||
|
@ -13,7 +14,19 @@ const ALLOWED_SOURCES: &[&str] = &[
|
|||
/// Checks for external package sources. `root` is the path to the directory that contains the
|
||||
/// workspace `Cargo.toml`.
|
||||
pub fn check(root: &Path, bad: &mut bool) {
|
||||
let submodules = build_helper::util::parse_gitmodules(root);
|
||||
for &(workspace, _, _) in crate::deps::WORKSPACES {
|
||||
// Skip if it's a submodule, not in a CI environment, and not initialized.
|
||||
//
|
||||
// This prevents enforcing developers to fetch submodules for tidy.
|
||||
if submodules.contains(&workspace.into())
|
||||
&& !CiEnv::is_ci()
|
||||
// If the directory is empty, we can consider it as an uninitialized submodule.
|
||||
&& read_dir(root.join(workspace)).unwrap().next().is_none()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// FIXME check other workspaces too
|
||||
// `Cargo.lock` of rust.
|
||||
let path = root.join(workspace).join("Cargo.lock");
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// can result in successful compilation.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ needs-symlink
|
||||
|
||||
use run_make_support::{create_symlink, cwd, fs_wrapper, rustc};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// See https://github.com/rust-lang/rust/issues/12459
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ needs-symlink
|
||||
|
||||
use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// See https://github.com/rust-lang/rust/pull/32828
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ needs-symlink
|
||||
|
||||
use run_make_support::{create_symlink, cwd, rustc};
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
|
|||
--> $DIR/issue-91827-extern-types-field-offset.rs:38:17
|
||||
|
|
||||
LL | let field = &x.a;
|
||||
| ^^^^ `extern type` does not have a known offset
|
||||
| ^^^^ `extern type` field does not have a known offset
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#![feature(extern_types)]
|
||||
|
||||
extern {
|
||||
type Opaque;
|
||||
}
|
||||
|
||||
struct ThinDst {
|
||||
x: u8,
|
||||
tail: Opaque,
|
||||
}
|
||||
|
||||
const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) };
|
||||
//~^ERROR: evaluation of constant value failed
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,9 @@
|
|||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/validation-ice-extern-type-field.rs:12:1
|
||||
|
|
||||
LL | const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) };
|
||||
| ^^^^^^^^^^^^^^^^^^ `extern type` field does not have a known offset
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
11
tests/ui/delegation/glob-traitless-qpath.rs
Normal file
11
tests/ui/delegation/glob-traitless-qpath.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
reuse <u8>::*; //~ ERROR qualified path without a trait in glob delegation
|
||||
reuse <()>::*; //~ ERROR qualified path without a trait in glob delegation
|
||||
}
|
||||
|
||||
fn main() {}
|
14
tests/ui/delegation/glob-traitless-qpath.stderr
Normal file
14
tests/ui/delegation/glob-traitless-qpath.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: qualified path without a trait in glob delegation
|
||||
--> $DIR/glob-traitless-qpath.rs:7:5
|
||||
|
|
||||
LL | reuse <u8>::*;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: qualified path without a trait in glob delegation
|
||||
--> $DIR/glob-traitless-qpath.rs:8:5
|
||||
|
|
||||
LL | reuse <()>::*;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -9,15 +9,11 @@ LL | const _: *const Foo = 0 as _;
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/stack-overflow-trait-infer-98842.rs:15:1
|
||||
|
|
||||
LL | const _: *const Foo = 0 as _;
|
||||
| ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
|
||||
|
|
||||
= note: the raw bytes of the constant (size: 4, align: 4) {
|
||||
00 00 00 00 │ ....
|
||||
}
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -9,15 +9,11 @@ LL | const _: *const Foo = 0 as _;
|
|||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/stack-overflow-trait-infer-98842.rs:15:1
|
||||
|
|
||||
LL | const _: *const Foo = 0 as _;
|
||||
| ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
|
||||
|
|
||||
= note: the raw bytes of the constant (size: 8, align: 8) {
|
||||
00 00 00 00 00 00 00 00 │ ........
|
||||
}
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -13,6 +13,6 @@ struct Foo(<&'static Foo as ::core::ops::Deref>::Target);
|
|||
// and it will infinitely recurse somewhere trying to figure out the
|
||||
// size of this pointer (is my guess):
|
||||
const _: *const Foo = 0 as _;
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
//~^ ERROR evaluation of constant value failed
|
||||
|
||||
pub fn main() {}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
error[E0391]: cycle detected when computing layout of `Foo`
|
||||
|
|
||||
= note: ...which requires computing layout of `<&'static Foo as core::ops::deref::Deref>::Target`...
|
||||
= note: ...which again requires computing layout of `Foo`, completing the cycle
|
||||
note: cycle used when const-evaluating + checking `_`
|
||||
--> $DIR/stack-overflow-trait-infer-98842.rs:13:1
|
||||
|
|
||||
LL | const _: *const Foo = 0 as _;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/stack-overflow-trait-infer-98842.rs:13:1
|
||||
|
|
||||
LL | const _: *const Foo = 0 as _;
|
||||
| ^^^^^^^^^^^^^^^^^^^ a cycle occurred during layout computation
|
||||
|
|
||||
= note: the raw bytes of the constant (size: 8, align: 8) {
|
||||
00 00 00 00 00 00 00 00 │ ........
|
||||
}
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0080, E0391.
|
||||
For more information about an error, try `rustc --explain E0080`.
|
Loading…
Add table
Reference in a new issue