Auto merge of #150135 - JonathanBrouwer:rollup-pn911bj, r=JonathanBrouwer
Rollup of 12 pull requests Successful merges: - rust-lang/rust#145933 (Expand `str_as_str` to more types) - rust-lang/rust#148849 (Set -Cpanic=abort in windows-msvc stack protector tests) - rust-lang/rust#149925 (`cfg_select!`: parse unused branches) - rust-lang/rust#149952 (Suggest struct pattern when destructuring Range with .. syntax) - rust-lang/rust#150022 (Generate macro expansion for rust compiler crates docs) - rust-lang/rust#150024 (Support recursive delegation) - rust-lang/rust#150048 (std_detect: AArch64 Darwin: expose SME F16F16 and B16B16 features) - rust-lang/rust#150083 (tests/run-make-cargo/same-crate-name-and-macro-name: New regression test) - rust-lang/rust#150102 (Fixed ICE for EII with multiple defaults due to duplicate definition in nameres) - rust-lang/rust#150124 (unstable.rs: fix typos in comments (implementatble -> implementable)) - rust-lang/rust#150125 (Port `#[rustc_lint_opt_deny_field_access]` to attribute parser) - rust-lang/rust#150126 (Subtree sync for rustc_codegen_cranelift) Failed merges: - rust-lang/rust#150127 (Port `#[rustc_lint_untracked_query_information]` and `#[rustc_lint_diagnostics]` to using attribute parsers) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
fcf67da039
70 changed files with 1254 additions and 224 deletions
|
|
@ -56,6 +56,8 @@ ast_lowering_coroutine_too_many_parameters =
|
|||
ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs
|
||||
.label = default fields are only supported on structs
|
||||
|
||||
ast_lowering_delegation_cycle_in_signature_resolution = encountered a cycle during delegation signature resolution
|
||||
ast_lowering_delegation_unresolved_callee = failed to resolve delegation callee
|
||||
ast_lowering_does_not_support_modifiers =
|
||||
the `{$class_name}` register class does not support template modifiers
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ use hir::{BodyId, HirId};
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::*;
|
||||
use rustc_attr_parsing::{AttributeParser, ShouldEmit};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::Target;
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
|
|
@ -55,6 +56,7 @@ use rustc_span::{DUMMY_SP, Ident, Span, Symbol};
|
|||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||
use crate::errors::{CycleInDelegationSignatureResolution, UnresolvedDelegationCallee};
|
||||
use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt};
|
||||
|
||||
pub(crate) struct DelegationResults<'hir> {
|
||||
|
|
@ -119,10 +121,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
delegation: &Delegation,
|
||||
item_id: NodeId,
|
||||
is_in_trait_impl: bool,
|
||||
) -> DelegationResults<'hir> {
|
||||
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
|
||||
let sig_id = self.get_delegation_sig_id(item_id, delegation.id, span, is_in_trait_impl);
|
||||
|
||||
let sig_id = self.get_delegation_sig_id(
|
||||
self.resolver.delegation_sig_resolution_nodes[&self.local_def_id(item_id)],
|
||||
span,
|
||||
);
|
||||
|
||||
match sig_id {
|
||||
Ok(sig_id) => {
|
||||
self.add_attributes_if_needed(span, sig_id);
|
||||
|
|
@ -238,24 +244,48 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn get_delegation_sig_id(
|
||||
&self,
|
||||
item_id: NodeId,
|
||||
path_id: NodeId,
|
||||
mut node_id: NodeId,
|
||||
span: Span,
|
||||
is_in_trait_impl: bool,
|
||||
) -> Result<DefId, ErrorGuaranteed> {
|
||||
let sig_id = if is_in_trait_impl { item_id } else { path_id };
|
||||
self.get_resolution_id(sig_id, span)
|
||||
let mut visited: FxHashSet<NodeId> = Default::default();
|
||||
|
||||
loop {
|
||||
visited.insert(node_id);
|
||||
|
||||
let Some(def_id) = self.get_resolution_id(node_id) else {
|
||||
return Err(self.tcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
format!(
|
||||
"LoweringContext: couldn't resolve node {:?} in delegation item",
|
||||
node_id
|
||||
),
|
||||
));
|
||||
};
|
||||
|
||||
// If def_id is in local crate and it corresponds to another delegation
|
||||
// it means that we refer to another delegation as a callee, so in order to obtain
|
||||
// a signature DefId we obtain NodeId of the callee delegation and try to get signature from it.
|
||||
if let Some(local_id) = def_id.as_local()
|
||||
&& let Some(next_node_id) =
|
||||
self.resolver.delegation_sig_resolution_nodes.get(&local_id)
|
||||
{
|
||||
node_id = *next_node_id;
|
||||
if visited.contains(&node_id) {
|
||||
// We encountered a cycle in the resolution, or delegation callee refers to non-existent
|
||||
// entity, in this case emit an error.
|
||||
return Err(match visited.len() {
|
||||
1 => self.dcx().emit_err(UnresolvedDelegationCallee { span }),
|
||||
_ => self.dcx().emit_err(CycleInDelegationSignatureResolution { span }),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Ok(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_resolution_id(&self, node_id: NodeId, span: Span) -> Result<DefId, ErrorGuaranteed> {
|
||||
let def_id =
|
||||
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id());
|
||||
def_id.ok_or_else(|| {
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
span,
|
||||
format!("LoweringContext: couldn't resolve node {:?} in delegation item", node_id),
|
||||
)
|
||||
})
|
||||
fn get_resolution_id(&self, node_id: NodeId) -> Option<DefId> {
|
||||
self.resolver.get_partial_res(node_id).and_then(|r| r.expect_full_res().opt_def_id())
|
||||
}
|
||||
|
||||
fn lower_delegation_generics(&mut self, span: Span) -> &'hir hir::Generics<'hir> {
|
||||
|
|
@ -271,8 +301,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Function parameter count, including C variadic `...` if present.
|
||||
fn param_count(&self, sig_id: DefId) -> (usize, bool /*c_variadic*/) {
|
||||
if let Some(local_sig_id) = sig_id.as_local() {
|
||||
// Map may be filled incorrectly due to recursive delegation.
|
||||
// Error will be emitted later during HIR ty lowering.
|
||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
||||
Some(sig) => (sig.param_count, sig.c_variadic),
|
||||
None => (0, false),
|
||||
|
|
@ -489,8 +517,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
|
||||
|
||||
let call = if self
|
||||
.get_resolution_id(delegation.id, span)
|
||||
.and_then(|def_id| Ok(self.is_method(def_id, span)))
|
||||
.get_resolution_id(delegation.id)
|
||||
.map(|def_id| self.is_method(def_id, span))
|
||||
.unwrap_or_default()
|
||||
&& delegation.qself.is_none()
|
||||
&& !has_generic_args
|
||||
|
|
|
|||
|
|
@ -475,3 +475,17 @@ pub(crate) struct UnionWithDefault {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_delegation_unresolved_callee)]
|
||||
pub(crate) struct UnresolvedDelegationCallee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_delegation_cycle_in_signature_resolution)]
|
||||
pub(crate) struct CycleInDelegationSignatureResolution {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
|
||||
}
|
||||
ItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, id, false);
|
||||
let delegation_results = self.lower_delegation(delegation, id);
|
||||
hir::ItemKind::Fn {
|
||||
sig: delegation_results.sig,
|
||||
ident: delegation_results.ident,
|
||||
|
|
@ -1026,7 +1026,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(*ident, generics, kind, ty.is_some())
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id, false);
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
let item_kind = hir::TraitItemKind::Fn(
|
||||
delegation_results.sig,
|
||||
hir::TraitFn::Provided(delegation_results.body_id),
|
||||
|
|
@ -1196,7 +1196,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}
|
||||
AssocItemKind::Delegation(box delegation) => {
|
||||
let delegation_results = self.lower_delegation(delegation, i.id, is_in_trait_impl);
|
||||
let delegation_results = self.lower_delegation(delegation, i.id);
|
||||
(
|
||||
delegation.ident,
|
||||
(
|
||||
|
|
|
|||
|
|
@ -28,6 +28,33 @@ pub struct CfgSelectBranches {
|
|||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||
}
|
||||
|
||||
impl CfgSelectBranches {
|
||||
/// Removes the top-most branch for which `predicate` returns `true`,
|
||||
/// or the wildcard if none of the reachable branches satisfied the predicate.
|
||||
pub fn pop_first_match<F>(&mut self, predicate: F) -> Option<(TokenStream, Span)>
|
||||
where
|
||||
F: Fn(&CfgEntry) -> bool,
|
||||
{
|
||||
for (index, (cfg, _, _)) in self.reachable.iter().enumerate() {
|
||||
if predicate(cfg) {
|
||||
let matched = self.reachable.remove(index);
|
||||
return Some((matched.1, matched.2));
|
||||
}
|
||||
}
|
||||
|
||||
self.wildcard.take().map(|(_, tts, span)| (tts, span))
|
||||
}
|
||||
|
||||
/// Consume this value and iterate over all the `TokenStream`s that it stores.
|
||||
pub fn into_iter_tts(self) -> impl Iterator<Item = (TokenStream, Span)> {
|
||||
let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span));
|
||||
let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span));
|
||||
let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span));
|
||||
|
||||
it1.chain(it2).chain(it3)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_cfg_select(
|
||||
p: &mut Parser<'_>,
|
||||
sess: &Session,
|
||||
|
|
|
|||
|
|
@ -117,11 +117,35 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintOptDenyFieldAccessParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
|
||||
let Some(arg) = args.list().and_then(MetaItemListParser::single) else {
|
||||
cx.expected_single_argument(cx.attr_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg
|
||||
else {
|
||||
cx.expected_string_literal(arg.span(), arg.lit());
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLintOptTyParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintOptTyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;
|
||||
}
|
||||
|
|
@ -130,7 +154,7 @@ pub(crate) struct RustcLintQueryInstabilityParser;
|
|||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
|
|
|
|||
|
|
@ -61,9 +61,9 @@ use crate::attributes::prototype::CustomMirParser;
|
|||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
|
||||
RustcMainParser, RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcLegacyConstGenericsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser,
|
||||
RustcLintQueryInstabilityParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
|
||||
RustcNoImplicitAutorefsParser, RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
|
|
@ -213,6 +213,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEndParser>,
|
||||
Single<RustcLayoutScalarValidRangeStartParser>,
|
||||
Single<RustcLegacyConstGenericsParser>,
|
||||
Single<RustcLintOptDenyFieldAccessParser>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<RustcScalableVectorParser>,
|
||||
Single<RustcSimdMonomorphizeLaneLimitParser>,
|
||||
|
|
|
|||
|
|
@ -1,22 +1,65 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{Expr, ast};
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
||||
|
||||
/// Selects the first arm whose predicate evaluates to true.
|
||||
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
|
||||
for (cfg, tt, arm_span) in branches.reachable {
|
||||
if let EvalConfigResult::True = attr::eval_config_entry(&ecx.sess, &cfg) {
|
||||
return Some((tt, arm_span));
|
||||
}
|
||||
}
|
||||
/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
|
||||
/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only
|
||||
/// keeps the parse result for the selected branch.
|
||||
struct CfgSelectResult<'cx, 'sess> {
|
||||
ecx: &'cx mut ExtCtxt<'sess>,
|
||||
site_span: Span,
|
||||
selected_tts: TokenStream,
|
||||
selected_span: Span,
|
||||
other_branches: CfgSelectBranches,
|
||||
}
|
||||
|
||||
branches.wildcard.map(|(_, tt, span)| (tt, span))
|
||||
fn tts_to_mac_result<'cx, 'sess>(
|
||||
ecx: &'cx mut ExtCtxt<'sess>,
|
||||
site_span: Span,
|
||||
tts: TokenStream,
|
||||
span: Span,
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
match ExpandResult::from_tts(ecx, tts, site_span, span, Ident::with_dummy_span(sym::cfg_select))
|
||||
{
|
||||
ExpandResult::Ready(x) => x,
|
||||
_ => unreachable!("from_tts always returns Ready"),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_to_parser_any_macro {
|
||||
($method_name:ident, $ret_ty:ty) => {
|
||||
fn $method_name(self: Box<Self>) -> Option<$ret_ty> {
|
||||
let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self;
|
||||
|
||||
for (tts, span) in self.other_branches.into_iter_tts() {
|
||||
let _ = tts_to_mac_result(ecx, site_span, tts, span).$method_name();
|
||||
}
|
||||
|
||||
tts_to_mac_result(ecx, site_span, selected_tts, selected_span).$method_name()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<'cx, 'sess> MacResult for CfgSelectResult<'cx, 'sess> {
|
||||
forward_to_parser_any_macro!(make_expr, Box<Expr>);
|
||||
forward_to_parser_any_macro!(make_stmts, SmallVec<[ast::Stmt; 1]>);
|
||||
forward_to_parser_any_macro!(make_items, SmallVec<[Box<ast::Item>; 1]>);
|
||||
|
||||
forward_to_parser_any_macro!(make_impl_items, SmallVec<[Box<ast::AssocItem>; 1]>);
|
||||
forward_to_parser_any_macro!(make_trait_impl_items, SmallVec<[Box<ast::AssocItem>; 1]>);
|
||||
forward_to_parser_any_macro!(make_trait_items, SmallVec<[Box<ast::AssocItem>; 1]>);
|
||||
forward_to_parser_any_macro!(make_foreign_items, SmallVec<[Box<ast::ForeignItem>; 1]>);
|
||||
|
||||
forward_to_parser_any_macro!(make_ty, Box<ast::Ty>);
|
||||
forward_to_parser_any_macro!(make_pat, Box<ast::Pat>);
|
||||
}
|
||||
|
||||
pub(super) fn expand_cfg_select<'cx>(
|
||||
|
|
@ -31,7 +74,7 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
Some(ecx.ecfg.features),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(branches) => {
|
||||
Ok(mut branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
|
|
@ -44,14 +87,17 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
|
||||
matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
|
||||
}) {
|
||||
let mac = CfgSelectResult {
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
selected_tts,
|
||||
selected_span,
|
||||
other_branches: branches,
|
||||
site_span: sp,
|
||||
};
|
||||
return ExpandResult::Ready(Box::new(mac));
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
|
||||
- name: Avoid installing rustc-dev
|
||||
run: |
|
||||
sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain
|
||||
sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain.toml
|
||||
rustfmt -v
|
||||
|
||||
- name: Rustfmt
|
||||
|
|
@ -88,7 +88,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
|
||||
- name: Set MinGW as the default toolchain
|
||||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
|
|
@ -158,7 +158,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
|
||||
- name: Install hyperfine
|
||||
run: |
|
||||
|
|
@ -207,7 +207,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }}
|
||||
|
||||
- name: Set MinGW as the default toolchain
|
||||
if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
||||
|
||||
- name: Test
|
||||
run: ./scripts/test_bootstrap.sh
|
||||
|
|
@ -40,7 +40,7 @@ jobs:
|
|||
uses: actions/cache@v4
|
||||
with:
|
||||
path: build/cg_clif
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
|
||||
key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }}
|
||||
|
||||
- name: Install ripgrep
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -259,6 +259,9 @@ unsafe fn test_simd() {
|
|||
test_mm_cvttps_epi32();
|
||||
test_mm_cvtsi128_si64();
|
||||
|
||||
#[cfg(not(jit))]
|
||||
test_mm_cvtps_ph();
|
||||
|
||||
test_mm_extract_epi8();
|
||||
test_mm_insert_epi16();
|
||||
test_mm_shuffle_epi8();
|
||||
|
|
@ -558,6 +561,21 @@ unsafe fn test_mm_cvttps_epi32() {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "f16c")]
|
||||
#[cfg(not(jit))]
|
||||
unsafe fn test_mm_cvtps_ph() {
|
||||
const F16_ONE: i16 = 0x3c00;
|
||||
const F16_TWO: i16 = 0x4000;
|
||||
const F16_THREE: i16 = 0x4200;
|
||||
const F16_FOUR: i16 = 0x4400;
|
||||
|
||||
let a = _mm_set_ps(1.0, 2.0, 3.0, 4.0);
|
||||
let r = _mm_cvtps_ph::<_MM_FROUND_CUR_DIRECTION>(a);
|
||||
let e = _mm_set_epi16(0, 0, 0, 0, F16_ONE, F16_TWO, F16_THREE, F16_FOUR);
|
||||
assert_eq_m128i(r, e);
|
||||
}
|
||||
|
||||
fn test_checked_mul() {
|
||||
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
|
||||
assert_eq!(u, None);
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-12-08"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
4
compiler/rustc_codegen_cranelift/rust-toolchain.toml
Normal file
4
compiler/rustc_codegen_cranelift/rust-toolchain.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-12-18"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
|
@ -22,8 +22,7 @@ case $1 in
|
|||
"prepare")
|
||||
echo "=> Installing new nightly"
|
||||
rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists
|
||||
sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain
|
||||
rustup component add rustfmt || true
|
||||
sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain.toml
|
||||
|
||||
echo "=> Uninstalling all old nightlies"
|
||||
for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do
|
||||
|
|
@ -35,7 +34,7 @@ case $1 in
|
|||
./y.sh prepare
|
||||
;;
|
||||
"commit")
|
||||
git add rust-toolchain
|
||||
git add rust-toolchain.toml
|
||||
git commit -m "Rustup to $(rustc -V)"
|
||||
;;
|
||||
"push")
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs
|
|||
rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic
|
||||
rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps
|
||||
rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # unimplemented simd_funnel_{shl,shr}
|
||||
rm -r tests/ui/scalable-vectors # scalable vectors are unsupported
|
||||
|
||||
# exotic linkages
|
||||
rm tests/incremental/hashes/function_interfaces.rs
|
||||
|
|
@ -53,23 +54,29 @@ rm tests/ui/sanitizer/kcfi-c-variadic.rs # same
|
|||
rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported
|
||||
rm tests/ui/delegation/fn-header.rs
|
||||
|
||||
# inline assembly features
|
||||
rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
|
||||
rm tests/ui/asm/global-asm-mono-sym-fn.rs # same
|
||||
rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same
|
||||
rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
|
||||
rm tests/ui/asm/label-operand.rs # same
|
||||
rm tests/ui/asm/may_unwind.rs # asm unwinding not supported
|
||||
rm tests/ui/asm/aarch64/may_unwind.rs # same
|
||||
|
||||
# misc unimplemented things
|
||||
rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
|
||||
rm -r tests/run-make/repr128-dwarf # debuginfo test
|
||||
rm -r tests/run-make/split-debuginfo # same
|
||||
rm -r tests/run-make/target-specs # i686 not supported by Cranelift
|
||||
rm -r tests/run-make/mismatching-target-triples # same
|
||||
rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly
|
||||
rm tests/ui/asm/global-asm-mono-sym-fn.rs # same
|
||||
rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same
|
||||
rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported
|
||||
rm tests/ui/asm/label-operand.rs # same
|
||||
rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes
|
||||
rm -r tests/run-make/used-proc-macro # used(linker) isn't supported yet
|
||||
rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same
|
||||
rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported
|
||||
rm -r tests/ui/explicit-tail-calls # tail calls
|
||||
rm -r tests/run-make/pointer-auth-link-with-c # pointer auth
|
||||
rm -r tests/ui/eii # EII not yet implemented
|
||||
rm -r tests/run-make/forced-unwind-terminate-pof # forced unwinding doesn't take precedence
|
||||
|
||||
# requires LTO
|
||||
rm -r tests/run-make/cdylib
|
||||
|
|
@ -78,6 +85,7 @@ rm -r tests/run-make/lto-*
|
|||
rm -r tests/run-make/reproducible-build-2
|
||||
rm -r tests/run-make/no-builtins-lto
|
||||
rm -r tests/run-make/reachable-extern-fn-available-lto
|
||||
rm -r tests/run-make/no-builtins-linker-plugin-lto
|
||||
|
||||
# coverage instrumentation
|
||||
rm tests/ui/consts/precise-drop-with-coverage.rs
|
||||
|
|
@ -87,6 +95,7 @@ rm -r tests/ui/instrument-coverage/
|
|||
# ==================
|
||||
rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations
|
||||
rm tests/ui/codegen/init-large-type.rs # same
|
||||
rm tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs # same
|
||||
rm tests/ui/statics/const_generics.rs # tests an optimization
|
||||
rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics
|
||||
|
||||
|
|
@ -143,6 +152,15 @@ rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path
|
|||
rm -r tests/run-make/export/extern-opt # something about rustc version mismatches
|
||||
rm -r tests/run-make/export # same
|
||||
rm -r tests/ui/compiletest-self-test/compile-flags-incremental.rs # needs compiletest compiled with panic=unwind
|
||||
rm tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs # something going wrong with stdlib source remapping
|
||||
rm tests/ui/consts/miri_unleashed/drop.rs # same
|
||||
rm tests/ui/error-emitter/multiline-removal-suggestion.rs # same
|
||||
rm tests/ui/lint/lint-const-item-mutation.rs # same
|
||||
rm tests/ui/lint/use-redundant/use-redundant-issue-71450.rs # same
|
||||
rm tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs # same
|
||||
rm tests/ui/specialization/const_trait_impl.rs # same
|
||||
rm tests/ui/thir-print/offset_of.rs # same
|
||||
rm tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs # same
|
||||
|
||||
# genuine bugs
|
||||
# ============
|
||||
|
|
@ -157,6 +175,7 @@ rm tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs # same
|
|||
rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493)
|
||||
rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables
|
||||
rm -r tests/run-make-cargo/rustdoc-scrape-examples-paths # FIXME(rust-lang/rust#145580) incr comp bug
|
||||
rm -r tests/incremental/extern_static/issue-49153.rs # assumes reference to undefined static gets optimized away
|
||||
|
||||
rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # really slow with unoptimized libstd
|
||||
rm tests/ui/process/process-panic-after-fork.rs # same
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ fn dep_symbol_lookup_fn(
|
|||
diag.emit();
|
||||
}
|
||||
Linkage::Dynamic => {
|
||||
dylib_paths.push(src.dylib.as_ref().unwrap().0.clone());
|
||||
dylib_paths.push(src.dylib.as_ref().unwrap().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1313,6 +1313,35 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>(
|
|||
ret.write_cvalue_transmute(fx, res);
|
||||
}
|
||||
|
||||
"llvm.x86.vcvtps2ph.128" => {
|
||||
// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_ph
|
||||
intrinsic_args!(fx, args => (a, _imm8); intrinsic);
|
||||
let a = a.load_scalar(fx);
|
||||
|
||||
let imm8 =
|
||||
if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1].node) {
|
||||
imm8
|
||||
} else {
|
||||
fx.tcx
|
||||
.dcx()
|
||||
.span_fatal(span, "Index argument for `_mm_cvtps_ph` is not a constant");
|
||||
};
|
||||
|
||||
let imm8 = imm8.to_u32();
|
||||
|
||||
codegen_inline_asm_inner(
|
||||
fx,
|
||||
&[InlineAsmTemplatePiece::String(format!("vcvtps2ph xmm0, xmm0, {imm8}").into())],
|
||||
&[CInlineAsmOperand::InOut {
|
||||
reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)),
|
||||
_late: true,
|
||||
in_value: a,
|
||||
out_place: Some(ret),
|
||||
}],
|
||||
InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
|
||||
);
|
||||
}
|
||||
|
||||
_ => {
|
||||
fx.tcx
|
||||
.dcx()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,3 @@
|
|||
|
||||
# Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust)
|
||||
[issue-links]
|
||||
|
||||
# Prevents mentions in commits to avoid users being spammed
|
||||
[no-mentions]
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ declare_features! (
|
|||
(internal, compiler_builtins, "1.13.0", None),
|
||||
/// Allows writing custom MIR
|
||||
(internal, custom_mir, "1.65.0", None),
|
||||
/// Implementation details of externally implementatble items
|
||||
/// Implementation details of externally implementable items
|
||||
(internal, eii_internals, "CURRENT_RUSTC_VERSION", None),
|
||||
/// Outputs useful `assert!` messages
|
||||
(unstable, generic_assert, "1.63.0", None),
|
||||
|
|
@ -503,7 +503,7 @@ declare_features! (
|
|||
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
|
||||
/// Allows using `#[export_stable]` which indicates that an item is exportable.
|
||||
(incomplete, export_stable, "1.88.0", Some(139939)),
|
||||
/// Externally implementatble items
|
||||
/// Externally implementable items
|
||||
(unstable, extern_item_impls, "CURRENT_RUSTC_VERSION", Some(125418)),
|
||||
/// Allows defining `extern type`s.
|
||||
(unstable, extern_types, "1.23.0", Some(43467)),
|
||||
|
|
|
|||
|
|
@ -931,6 +931,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_legacy_const_generics]`
|
||||
RustcLegacyConstGenerics { fn_indexes: ThinVec<(usize, Span)>, attr_span: Span },
|
||||
|
||||
/// Represents `#[rustc_lint_opt_deny_field_access]`
|
||||
RustcLintOptDenyFieldAccess { lint_message: Symbol },
|
||||
|
||||
/// Represents `#[rustc_lint_opt_ty]`
|
||||
RustcLintOptTy,
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeEnd(..) => Yes,
|
||||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcLegacyConstGenerics { .. } => Yes,
|
||||
RustcLintOptDenyFieldAccess { .. } => Yes,
|
||||
RustcLintOptTy => Yes,
|
||||
RustcLintQueryInstability => Yes,
|
||||
RustcMain => No,
|
||||
|
|
|
|||
|
|
@ -401,12 +401,6 @@ fn check_constraints<'tcx>(
|
|||
}));
|
||||
};
|
||||
|
||||
if let Some(local_sig_id) = sig_id.as_local()
|
||||
&& tcx.hir_opt_delegation_sig_id(local_sig_id).is_some()
|
||||
{
|
||||
emit("recursive delegation is not supported yet");
|
||||
}
|
||||
|
||||
if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic {
|
||||
// See issue #127443 for explanation.
|
||||
emit("delegation to C-variadic functions is not allowed");
|
||||
|
|
|
|||
|
|
@ -668,17 +668,12 @@ impl LateLintPass<'_> for BadOptAccess {
|
|||
|
||||
for field in adt_def.all_fields() {
|
||||
if field.name == target.name
|
||||
&& let Some(attr) =
|
||||
cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access)
|
||||
&& let Some(items) = attr.meta_item_list()
|
||||
&& let Some(item) = items.first()
|
||||
&& let Some(lit) = item.lit()
|
||||
&& let ast::LitKind::Str(val, _) = lit.kind
|
||||
&& let Some(lint_message) = find_attr!(cx.tcx.get_all_attrs(field.did), AttributeKind::RustcLintOptDenyFieldAccess { lint_message, } => lint_message)
|
||||
{
|
||||
cx.emit_span_lint(
|
||||
BAD_OPT_ACCESS,
|
||||
expr.span,
|
||||
BadOptAccessDiag { msg: val.as_str() },
|
||||
BadOptAccessDiag { msg: lint_message.as_str() },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,6 +221,9 @@ pub struct ResolverAstLowering {
|
|||
|
||||
/// Information about functions signatures for delegation items expansion
|
||||
pub delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
|
||||
// NodeIds (either delegation.id or item_id in case of a trait impl) for signature resolution,
|
||||
// for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914
|
||||
pub delegation_sig_resolution_nodes: LocalDefIdMap<ast::NodeId>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
|
|
|
|||
|
|
@ -473,9 +473,6 @@ passes_rustc_legacy_const_generics_only =
|
|||
#[rustc_legacy_const_generics] functions must only have const generics
|
||||
.label = non-const generic parameter
|
||||
|
||||
passes_rustc_lint_opt_deny_field_access =
|
||||
`#[rustc_lint_opt_deny_field_access]` should be applied to a field
|
||||
.label = not a field
|
||||
|
||||
passes_rustc_pub_transparent =
|
||||
attribute should be applied to `#[repr(transparent)]` types
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::RustcNoImplicitAutorefs
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcLintOptDenyFieldAccess { .. }
|
||||
| AttributeKind::RustcLintOptTy
|
||||
| AttributeKind::RustcLintQueryInstability
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
|
|
@ -314,9 +315,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::rustc_lint_diagnostics, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_lint_opt_deny_field_access, ..] => {
|
||||
self.check_rustc_lint_opt_deny_field_access(attr, span, target)
|
||||
}
|
||||
[sym::rustc_clean, ..]
|
||||
| [sym::rustc_dirty, ..]
|
||||
| [sym::rustc_if_this_changed, ..]
|
||||
|
|
@ -1251,18 +1249,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field.
|
||||
fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
|
||||
match target {
|
||||
Target::Field => {}
|
||||
_ => {
|
||||
self.tcx
|
||||
.dcx()
|
||||
.emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
|
||||
/// option is passed to the compiler.
|
||||
fn check_rustc_dirty_clean(&self, attr: &Attribute) {
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ pub(crate) fn check_externally_implementable_items<'tcx>(tcx: TyCtxt<'tcx>, ():
|
|||
}
|
||||
|
||||
if default_impls.len() > 1 {
|
||||
panic!("multiple not supported right now");
|
||||
let decl_span = tcx.def_ident_span(decl_did).unwrap();
|
||||
tcx.dcx().span_delayed_bug(decl_span, "multiple not supported right now");
|
||||
}
|
||||
|
||||
let (local_impl, is_default) =
|
||||
|
|
|
|||
|
|
@ -412,15 +412,6 @@ pub(crate) struct UnusedMultiple {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_rustc_lint_opt_deny_field_access)]
|
||||
pub(crate) struct RustcLintOptDenyFieldAccess {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_collapse_debuginfo)]
|
||||
pub(crate) struct CollapseDebuginfo {
|
||||
|
|
|
|||
|
|
@ -2928,7 +2928,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
item.id,
|
||||
LifetimeBinderKind::Function,
|
||||
span,
|
||||
|this| this.resolve_delegation(delegation),
|
||||
|this| this.resolve_delegation(delegation, item.id, false),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -3257,7 +3257,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
item.id,
|
||||
LifetimeBinderKind::Function,
|
||||
delegation.path.segments.last().unwrap().ident.span,
|
||||
|this| this.resolve_delegation(delegation),
|
||||
|this| this.resolve_delegation(delegation, item.id, false),
|
||||
);
|
||||
}
|
||||
AssocItemKind::Type(box TyAlias { generics, .. }) => self
|
||||
|
|
@ -3550,7 +3550,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
|i, s, c| MethodNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
this.resolve_delegation(delegation)
|
||||
this.resolve_delegation(delegation, item.id, trait_id.is_some());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -3699,17 +3699,30 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
fn resolve_delegation(&mut self, delegation: &'ast Delegation) {
|
||||
fn resolve_delegation(
|
||||
&mut self,
|
||||
delegation: &'ast Delegation,
|
||||
item_id: NodeId,
|
||||
is_in_trait_impl: bool,
|
||||
) {
|
||||
self.smart_resolve_path(
|
||||
delegation.id,
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
PathSource::Delegation,
|
||||
);
|
||||
|
||||
if let Some(qself) = &delegation.qself {
|
||||
self.visit_ty(&qself.ty);
|
||||
}
|
||||
|
||||
self.visit_path(&delegation.path);
|
||||
|
||||
self.r.delegation_sig_resolution_nodes.insert(
|
||||
self.r.local_def_id(item_id),
|
||||
if is_in_trait_impl { item_id } else { delegation.id },
|
||||
);
|
||||
|
||||
let Some(body) = &delegation.body else { return };
|
||||
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
|
||||
let span = delegation.path.segments.last().unwrap().ident.span;
|
||||
|
|
@ -4294,7 +4307,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn smart_resolve_path_fragment(
|
||||
&mut self,
|
||||
qself: &Option<Box<QSelf>>,
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
|
||||
self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
|
||||
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
|
||||
self.suggest_range_struct_destructuring(&mut err, path, source);
|
||||
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
||||
|
||||
if let Some((span, label)) = base_error.span_label {
|
||||
|
|
@ -1383,6 +1384,84 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_range_struct_destructuring(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
path: &[Segment],
|
||||
source: PathSource<'_, '_, '_>,
|
||||
) {
|
||||
if !matches!(source, PathSource::Pat | PathSource::TupleStruct(..) | PathSource::Expr(..)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(pat) = self.diag_metadata.current_pat else { return };
|
||||
let ast::PatKind::Range(start, end, end_kind) = &pat.kind else { return };
|
||||
|
||||
let [segment] = path else { return };
|
||||
let failing_span = segment.ident.span;
|
||||
|
||||
let in_start = start.as_ref().is_some_and(|e| e.span.contains(failing_span));
|
||||
let in_end = end.as_ref().is_some_and(|e| e.span.contains(failing_span));
|
||||
|
||||
if !in_start && !in_end {
|
||||
return;
|
||||
}
|
||||
|
||||
let start_snippet =
|
||||
start.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
|
||||
let end_snippet =
|
||||
end.as_ref().and_then(|e| self.r.tcx.sess.source_map().span_to_snippet(e.span).ok());
|
||||
|
||||
let field = |name: &str, val: String| {
|
||||
if val == name { val } else { format!("{name}: {val}") }
|
||||
};
|
||||
|
||||
let mut resolve_short_name = |short: Symbol, full: &str| -> String {
|
||||
let ident = Ident::with_dummy_span(short);
|
||||
let path = Segment::from_path(&Path::from_ident(ident));
|
||||
|
||||
match self.resolve_path(&path, Some(TypeNS), None, PathSource::Type) {
|
||||
PathResult::NonModule(..) => short.to_string(),
|
||||
_ => full.to_string(),
|
||||
}
|
||||
};
|
||||
// FIXME(new_range): Also account for new range types
|
||||
let (struct_path, fields) = match (start_snippet, end_snippet, &end_kind.node) {
|
||||
(Some(start), Some(end), ast::RangeEnd::Excluded) => (
|
||||
resolve_short_name(sym::Range, "std::ops::Range"),
|
||||
vec![field("start", start), field("end", end)],
|
||||
),
|
||||
(Some(start), Some(end), ast::RangeEnd::Included(_)) => (
|
||||
resolve_short_name(sym::RangeInclusive, "std::ops::RangeInclusive"),
|
||||
vec![field("start", start), field("end", end)],
|
||||
),
|
||||
(Some(start), None, _) => (
|
||||
resolve_short_name(sym::RangeFrom, "std::ops::RangeFrom"),
|
||||
vec![field("start", start)],
|
||||
),
|
||||
(None, Some(end), ast::RangeEnd::Excluded) => {
|
||||
(resolve_short_name(sym::RangeTo, "std::ops::RangeTo"), vec![field("end", end)])
|
||||
}
|
||||
(None, Some(end), ast::RangeEnd::Included(_)) => (
|
||||
resolve_short_name(sym::RangeToInclusive, "std::ops::RangeToInclusive"),
|
||||
vec![field("end", end)],
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
pat.span,
|
||||
format!("if you meant to destructure a range use a struct pattern"),
|
||||
format!("{} {{ {} }}", struct_path, fields.join(", ")),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
err.note(
|
||||
"range patterns match against the start and end of a range; \
|
||||
to bind the components, use a struct pattern",
|
||||
);
|
||||
}
|
||||
|
||||
fn suggest_swapping_misplaced_self_ty_and_trait(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,7 @@ pub struct Resolver<'ra, 'tcx> {
|
|||
/// Amount of lifetime parameters for each item in the crate.
|
||||
item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
|
||||
delegation_fn_sigs: LocalDefIdMap<DelegationFnSig>,
|
||||
delegation_sig_resolution_nodes: LocalDefIdMap<NodeId>,
|
||||
|
||||
main_def: Option<MainDefinition> = None,
|
||||
trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
|
||||
|
|
@ -1693,6 +1694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
current_crate_outer_attr_insert_span,
|
||||
mods_with_parse_errors: Default::default(),
|
||||
impl_trait_names: Default::default(),
|
||||
delegation_sig_resolution_nodes: Default::default(),
|
||||
..
|
||||
};
|
||||
|
||||
|
|
@ -1821,6 +1823,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
lifetime_elision_allowed: self.lifetime_elision_allowed,
|
||||
lint_buffer: Steal::new(self.lint_buffer),
|
||||
delegation_fn_sigs: self.delegation_fn_sigs,
|
||||
delegation_sig_resolution_nodes: self.delegation_sig_resolution_nodes,
|
||||
};
|
||||
ResolverOutputs { global_ctxt, ast_lowering }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,30 @@ impl ByteStr {
|
|||
ByteStr::from_bytes(bytes.as_ref())
|
||||
}
|
||||
|
||||
/// Returns the same string as `&ByteStr`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&ByteStr`, but
|
||||
/// it helps dereferencing other "container" types,
|
||||
/// for example `Box<ByteStr>` or `Arc<ByteStr>`.
|
||||
#[inline]
|
||||
// #[unstable(feature = "str_as_str", issue = "130366")]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub const fn as_byte_str(&self) -> &ByteStr {
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the same string as `&mut ByteStr`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&mut ByteStr`, but
|
||||
/// it helps dereferencing other "container" types,
|
||||
/// for example `Box<ByteStr>` or `MutexGuard<ByteStr>`.
|
||||
#[inline]
|
||||
// #[unstable(feature = "str_as_str", issue = "130366")]
|
||||
#[unstable(feature = "bstr", issue = "134915")]
|
||||
pub const fn as_mut_byte_str(&mut self) -> &mut ByteStr {
|
||||
self
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[unstable(feature = "bstr_internals", issue = "none")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -648,6 +648,17 @@ impl CStr {
|
|||
pub fn display(&self) -> impl fmt::Display {
|
||||
crate::bstr::ByteStr::from_bytes(self.to_bytes())
|
||||
}
|
||||
|
||||
/// Returns the same string as a string slice `&CStr`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&CStr`, but
|
||||
/// it helps dereferencing other string-like types to string slices,
|
||||
/// for example references to `Box<CStr>` or `Arc<CStr>`.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_as_str", issue = "130366")]
|
||||
pub const fn as_c_str(&self) -> &CStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "c_string_eq_c_str", since = "1.90.0")]
|
||||
|
|
|
|||
|
|
@ -4908,6 +4908,28 @@ impl<T> [T] {
|
|||
|
||||
if start <= self.len() && end <= self.len() { Some(start..end) } else { None }
|
||||
}
|
||||
|
||||
/// Returns the same slice `&[T]`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&[T]`, but
|
||||
/// it helps dereferencing other "container" types to slices,
|
||||
/// for example `Box<[T]>` or `Arc<[T]>`.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_as_str", issue = "130366")]
|
||||
pub const fn as_slice(&self) -> &[T] {
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns the same slice `&mut [T]`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&mut [T]`, but
|
||||
/// it helps dereferencing other "container" types to slices,
|
||||
/// for example `Box<[T]>` or `MutexGuard<[T]>`.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_as_str", issue = "130366")]
|
||||
pub const fn as_mut_slice(&mut self) -> &mut [T] {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> [MaybeUninit<T>] {
|
||||
|
|
|
|||
|
|
@ -1278,6 +1278,17 @@ impl OsStr {
|
|||
pub fn display(&self) -> Display<'_> {
|
||||
Display { os_str: self }
|
||||
}
|
||||
|
||||
/// Returns the same string as a string slice `&OsStr`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&OsStr`, but
|
||||
/// it helps dereferencing other string-like types to string slices,
|
||||
/// for example references to `Box<OsStr>` or `Arc<OsStr>`.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_as_str", issue = "130366")]
|
||||
pub const fn as_os_str(&self) -> &OsStr {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "box_from_os_str", since = "1.17.0")]
|
||||
|
|
|
|||
|
|
@ -3206,6 +3206,17 @@ impl Path {
|
|||
Display { inner: self.inner.display() }
|
||||
}
|
||||
|
||||
/// Returns the same path as `&Path`.
|
||||
///
|
||||
/// This method is redundant when used directly on `&Path`, but
|
||||
/// it helps dereferencing other `PathBuf`-like types to `Path`s,
|
||||
/// for example references to `Box<Path>` or `Arc<Path>`.
|
||||
#[inline]
|
||||
#[unstable(feature = "str_as_str", issue = "130366")]
|
||||
pub const fn as_path(&self) -> &Path {
|
||||
self
|
||||
}
|
||||
|
||||
/// Queries the file system to get information about a file, directory, etc.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
let sme = _sysctlbyname(c"hw.optional.arm.FEAT_SME");
|
||||
let sme2 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2");
|
||||
let sme2p1 = _sysctlbyname(c"hw.optional.arm.FEAT_SME2p1");
|
||||
let sme_b16b16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_B16B16");
|
||||
let sme_f16f16 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F16F16");
|
||||
let sme_f64f64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_F64F64");
|
||||
let sme_i16i64 = _sysctlbyname(c"hw.optional.arm.FEAT_SME_I16I64");
|
||||
let ssbs = _sysctlbyname(c"hw.optional.arm.FEAT_SSBS");
|
||||
|
|
@ -153,6 +155,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
enable_feature(Feature::sme, sme);
|
||||
enable_feature(Feature::sme2, sme2);
|
||||
enable_feature(Feature::sme2p1, sme2p1);
|
||||
enable_feature(Feature::sme_b16b16, sme_b16b16);
|
||||
enable_feature(Feature::sme_f16f16, sme_f16f16);
|
||||
enable_feature(Feature::sme_f64f64, sme_f64f64);
|
||||
enable_feature(Feature::sme_i16i64, sme_i16i64);
|
||||
enable_feature(Feature::ssbs, ssbs);
|
||||
|
|
|
|||
|
|
@ -932,6 +932,7 @@ impl Step for Rustc {
|
|||
// see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222
|
||||
// If there is any bug, please comment out the next line.
|
||||
cargo.rustdocflag("--generate-link-to-definition");
|
||||
cargo.rustdocflag("--generate-macro-expansion");
|
||||
|
||||
compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
|
||||
cargo.arg("-Zskip-rustdoc-fingerprint");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
//@ [strong] compile-flags: -Z stack-protector=strong
|
||||
//@ [basic] compile-flags: -Z stack-protector=basic
|
||||
//@ [none] compile-flags: -Z stack-protector=none
|
||||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
|
||||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort -Cdebuginfo=1
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![allow(internal_features)]
|
||||
|
|
@ -39,6 +39,8 @@ pub fn array_char(f: fn(*const char)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_1
|
||||
|
|
@ -55,6 +57,8 @@ pub fn array_u8_1(f: fn(*const u8)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_small:
|
||||
|
|
@ -72,6 +76,8 @@ pub fn array_u8_small(f: fn(*const u8)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_large:
|
||||
|
|
@ -88,6 +94,8 @@ pub fn array_u8_large(f: fn(*const u8)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -107,6 +115,8 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_var_addr_used_indirectly
|
||||
|
|
@ -134,6 +144,8 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_string_addr_taken
|
||||
|
|
@ -143,28 +155,15 @@ pub fn local_string_addr_taken(f: fn(&String)) {
|
|||
f(&x);
|
||||
|
||||
// Taking the address of the local variable `x` leads to stack smash
|
||||
// protection with the `strong` heuristic, but not with the `basic`
|
||||
// heuristic. It does not matter that the reference is not mut.
|
||||
//
|
||||
// An interesting note is that a similar function in C++ *would* be
|
||||
// protected by the `basic` heuristic, because `std::string` has a char
|
||||
// array internally as a small object optimization:
|
||||
// ```
|
||||
// cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
|
||||
// #include <string>
|
||||
// void f(void (*g)(const std::string&)) {
|
||||
// std::string x;
|
||||
// g(x);
|
||||
// }
|
||||
// EOF
|
||||
// ```
|
||||
//
|
||||
// protection. It does not matter that the reference is not mut.
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// basic-NOT: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
pub trait SelfByRef {
|
||||
|
|
@ -194,6 +193,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
pub struct Gigastruct {
|
||||
|
|
@ -231,6 +232,8 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_large_var_cloned
|
||||
|
|
@ -260,6 +263,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -300,6 +305,8 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: alloca_large_compile_time_constant_arg
|
||||
|
|
@ -312,6 +319,8 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: alloca_dynamic_arg
|
||||
|
|
@ -324,14 +333,14 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
||||
// The question then is: in what ways can Rust code generate array-`alloca`
|
||||
// LLVM instructions? This appears to only be generated by
|
||||
// rustc_codegen_ssa::traits::Builder::array_alloca() through
|
||||
// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
|
||||
// this is support for the "unsized locals" unstable feature:
|
||||
// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
|
||||
// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized().
|
||||
|
||||
// CHECK-LABEL: unsized_fn_param
|
||||
#[no_mangle]
|
||||
|
|
@ -346,14 +355,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
|||
// alloca, and is therefore not protected by the `strong` or `basic`
|
||||
// heuristics.
|
||||
|
||||
// We should have a __security_check_cookie call in `all` and `strong` modes but
|
||||
// LLVM does not support generating stack protectors in functions with funclet
|
||||
// based EH personalities.
|
||||
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
|
||||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .cv_fpo_endproc
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
//@ [strong] compile-flags: -Z stack-protector=strong
|
||||
//@ [basic] compile-flags: -Z stack-protector=basic
|
||||
//@ [none] compile-flags: -Z stack-protector=none
|
||||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
|
||||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
|
@ -25,6 +25,7 @@ pub fn emptyfn() {
|
|||
// CHECK-LABEL: array_char
|
||||
#[no_mangle]
|
||||
pub fn array_char(f: fn(*const char)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = ['c'; 1];
|
||||
let b = ['d'; 3];
|
||||
let c = ['e'; 15];
|
||||
|
|
@ -38,11 +39,14 @@ pub fn array_char(f: fn(*const char)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_1
|
||||
#[no_mangle]
|
||||
pub fn array_u8_1(f: fn(*const u8)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = [0u8; 1];
|
||||
f(&a as *const _);
|
||||
|
||||
|
|
@ -54,11 +58,14 @@ pub fn array_u8_1(f: fn(*const u8)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_small:
|
||||
#[no_mangle]
|
||||
pub fn array_u8_small(f: fn(*const u8)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = [0u8; 2];
|
||||
let b = [0u8; 7];
|
||||
f(&a as *const _);
|
||||
|
|
@ -71,11 +78,14 @@ pub fn array_u8_small(f: fn(*const u8)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: array_u8_large:
|
||||
#[no_mangle]
|
||||
pub fn array_u8_large(f: fn(*const u8)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = [0u8; 9];
|
||||
f(&a as *const _);
|
||||
|
||||
|
|
@ -87,6 +97,8 @@ pub fn array_u8_large(f: fn(*const u8)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
|
@ -95,6 +107,7 @@ pub struct ByteSizedNewtype(u8);
|
|||
// CHECK-LABEL: array_bytesizednewtype_9:
|
||||
#[no_mangle]
|
||||
pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = [ByteSizedNewtype(0); 9];
|
||||
f(&a as *const _);
|
||||
|
||||
|
|
@ -106,11 +119,14 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_var_addr_used_indirectly
|
||||
#[no_mangle]
|
||||
pub fn local_var_addr_used_indirectly(f: fn(bool)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let a = 5;
|
||||
let a_addr = &a as *const _ as usize;
|
||||
f(a_addr & 0x10 == 0);
|
||||
|
|
@ -133,6 +149,8 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_string_addr_taken
|
||||
|
|
@ -143,31 +161,11 @@ pub fn local_string_addr_taken(f: fn(&String)) {
|
|||
f(&x);
|
||||
|
||||
// Taking the address of the local variable `x` leads to stack smash
|
||||
// protection with the `strong` heuristic, but not with the `basic`
|
||||
// heuristic. It does not matter that the reference is not mut.
|
||||
//
|
||||
// An interesting note is that a similar function in C++ *would* be
|
||||
// protected by the `basic` heuristic, because `std::string` has a char
|
||||
// array internally as a small object optimization:
|
||||
// ```
|
||||
// cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
|
||||
// #include <string>
|
||||
// void f(void (*g)(const std::string&)) {
|
||||
// std::string x;
|
||||
// g(x);
|
||||
// }
|
||||
// EOF
|
||||
// ```
|
||||
//
|
||||
// protection. It does not matter that the reference is not mut.
|
||||
|
||||
// We should have a __security_check_cookie call in `all` and `strong` modes but
|
||||
// LLVM does not support generating stack protectors in functions with funclet
|
||||
// based EH personalities.
|
||||
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
|
||||
// basic-NOT: __security_check_cookie
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
|
|
@ -187,6 +185,7 @@ impl SelfByRef for i32 {
|
|||
// CHECK-LABEL: local_var_addr_taken_used_locally_only
|
||||
#[no_mangle]
|
||||
pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let x = factory();
|
||||
let g = x.f();
|
||||
sink(g);
|
||||
|
|
@ -201,6 +200,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
pub struct Gigastruct {
|
||||
|
|
@ -214,6 +215,7 @@ pub struct Gigastruct {
|
|||
// CHECK-LABEL: local_large_var_moved
|
||||
#[no_mangle]
|
||||
pub fn local_large_var_moved(f: fn(Gigastruct)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 };
|
||||
f(x);
|
||||
|
||||
|
|
@ -238,11 +240,14 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: local_large_var_cloned
|
||||
#[no_mangle]
|
||||
pub fn local_large_var_cloned(f: fn(Gigastruct)) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 });
|
||||
|
||||
// A new instance of `Gigastruct` is passed to `f()`, without any apparent
|
||||
|
|
@ -267,6 +272,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
|
|||
// basic: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -300,6 +307,7 @@ extern "C" {
|
|||
// CHECK-LABEL: alloca_small_compile_time_constant_arg
|
||||
#[no_mangle]
|
||||
pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
f(unsafe { alloca(8) });
|
||||
|
||||
// all: __security_check_cookie
|
||||
|
|
@ -307,11 +315,14 @@ pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: alloca_large_compile_time_constant_arg
|
||||
#[no_mangle]
|
||||
pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
f(unsafe { alloca(9) });
|
||||
|
||||
// all: __security_check_cookie
|
||||
|
|
@ -319,11 +330,14 @@ pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// CHECK-LABEL: alloca_dynamic_arg
|
||||
#[no_mangle]
|
||||
pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
f(unsafe { alloca(n) });
|
||||
|
||||
// all: __security_check_cookie
|
||||
|
|
@ -331,18 +345,19 @@ pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) {
|
|||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// The question then is: in what ways can Rust code generate array-`alloca`
|
||||
// LLVM instructions? This appears to only be generated by
|
||||
// rustc_codegen_ssa::traits::Builder::array_alloca() through
|
||||
// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
|
||||
// this is support for the "unsized locals" unstable feature:
|
||||
// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
|
||||
// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized().
|
||||
|
||||
// CHECK-LABEL: unsized_fn_param
|
||||
#[no_mangle]
|
||||
pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
let n = if l { 1 } else { 2 };
|
||||
f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from
|
||||
|
||||
|
|
@ -353,14 +368,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
|
|||
// alloca, and is therefore not protected by the `strong` or `basic`
|
||||
// heuristics.
|
||||
|
||||
// We should have a __security_check_cookie call in `all` and `strong` modes but
|
||||
// LLVM does not support generating stack protectors in functions with funclet
|
||||
// based EH personalities.
|
||||
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
|
||||
// basic-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@
|
|||
//@ [r84] needs-llvm-components: x86
|
||||
//@ [r85] compile-flags: --target x86_64-unknown-redox
|
||||
//@ [r85] needs-llvm-components: x86
|
||||
//@ compile-flags: -Z stack-protector=all
|
||||
//@ compile-flags: -Z stack-protector=all -Cpanic=abort
|
||||
//@ compile-flags: -C opt-level=2
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "consumer"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
mylib_v1 = { path = "../mylib_v1", package = "mylib" }
|
||||
mylib_v2 = { path = "../mylib_v2", package = "mylib" }
|
||||
|
||||
# Avoid interference with root workspace when casually testing
|
||||
[workspace]
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
let v1 = mylib_v1::my_macro!();
|
||||
assert_eq!(v1, "version 1");
|
||||
|
||||
let v2 = mylib_v2::my_macro!();
|
||||
assert_eq!(v2, "version 2");
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "mylib"
|
||||
version = "1.0.0"
|
||||
|
||||
# Avoid interference with root workspace when casually testing
|
||||
[workspace]
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#[macro_export]
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
"version 1"
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "mylib"
|
||||
version = "2.0.0"
|
||||
|
||||
# Avoid interference with root workspace when casually testing
|
||||
[workspace]
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#[macro_export]
|
||||
macro_rules! my_macro {
|
||||
() => {
|
||||
"version 2"
|
||||
};
|
||||
}
|
||||
13
tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs
Normal file
13
tests/run-make-cargo/same-crate-name-and-macro-name/rmake.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
//! Regression test for
|
||||
//! <https://github.com/rust-lang/rust/issues/71259#issuecomment-615879925>
|
||||
//! (that particular comment describes the issue well).
|
||||
//!
|
||||
//! We test that two library crates with the same name can export macros with
|
||||
//! the same name without causing interference when both are used in another
|
||||
//! crate.
|
||||
|
||||
use run_make_support::cargo;
|
||||
|
||||
fn main() {
|
||||
cargo().current_dir("consumer").arg("run").run();
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn foo() {}
|
||||
|
||||
reuse foo as bar;
|
||||
pub reuse bar as goo;
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// FIXME(fn_delegation): `recursive delegation` error should be emitted here
|
||||
trait Trait {
|
||||
reuse Trait::foo { &self.0 }
|
||||
//~^ ERROR failed to resolve delegation callee
|
||||
}
|
||||
|
||||
reuse foo;
|
||||
//~^ ERROR cycle detected when computing generics of `foo`
|
||||
//~^ ERROR failed to resolve delegation callee
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
error[E0391]: cycle detected when computing generics of `foo`
|
||||
error: failed to resolve delegation callee
|
||||
--> $DIR/ice-issue-124347.rs:5:18
|
||||
|
|
||||
LL | reuse Trait::foo { &self.0 }
|
||||
| ^^^
|
||||
|
||||
error: failed to resolve delegation callee
|
||||
--> $DIR/ice-issue-124347.rs:9:7
|
||||
|
|
||||
LL | reuse foo;
|
||||
| ^^^
|
||||
|
|
||||
= note: ...which immediately requires computing generics of `foo` again
|
||||
note: cycle used when checking that `foo` is well-formed
|
||||
--> $DIR/ice-issue-124347.rs:9:7
|
||||
|
|
||||
LL | reuse foo;
|
||||
| ^^^
|
||||
= 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: aborting due to 1 previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
||||
|
|
|
|||
54
tests/ui/delegation/recursive-delegation-errors.rs
Normal file
54
tests/ui/delegation/recursive-delegation-errors.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
|
||||
mod first_mod {
|
||||
reuse foo;
|
||||
//~^ ERROR failed to resolve delegation callee
|
||||
}
|
||||
|
||||
mod second_mod {
|
||||
reuse foo as bar;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse bar as foo;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
}
|
||||
|
||||
mod third_mod {
|
||||
reuse foo as foo1;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse foo1 as foo2;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse foo2 as foo3;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse foo3 as foo4;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse foo4 as foo5;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse foo5 as foo;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
}
|
||||
|
||||
mod fourth_mod {
|
||||
trait Trait {
|
||||
reuse Trait::foo as bar;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
reuse Trait::bar as foo;
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
}
|
||||
}
|
||||
|
||||
mod fifth_mod {
|
||||
reuse super::fifth_mod::{bar as foo, foo as bar};
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
//~| ERROR encountered a cycle during delegation signature resolution
|
||||
|
||||
trait GlobReuse {
|
||||
reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
|
||||
//~^ ERROR encountered a cycle during delegation signature resolution
|
||||
//~| ERROR encountered a cycle during delegation signature resolution
|
||||
//~| ERROR encountered a cycle during delegation signature resolution
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
98
tests/ui/delegation/recursive-delegation-errors.stderr
Normal file
98
tests/ui/delegation/recursive-delegation-errors.stderr
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
error: failed to resolve delegation callee
|
||||
--> $DIR/recursive-delegation-errors.rs:6:11
|
||||
|
|
||||
LL | reuse foo;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:11:11
|
||||
|
|
||||
LL | reuse foo as bar;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:13:11
|
||||
|
|
||||
LL | reuse bar as foo;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:18:11
|
||||
|
|
||||
LL | reuse foo as foo1;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:20:11
|
||||
|
|
||||
LL | reuse foo1 as foo2;
|
||||
| ^^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:22:11
|
||||
|
|
||||
LL | reuse foo2 as foo3;
|
||||
| ^^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:24:11
|
||||
|
|
||||
LL | reuse foo3 as foo4;
|
||||
| ^^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:26:11
|
||||
|
|
||||
LL | reuse foo4 as foo5;
|
||||
| ^^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:28:11
|
||||
|
|
||||
LL | reuse foo5 as foo;
|
||||
| ^^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:34:22
|
||||
|
|
||||
LL | reuse Trait::foo as bar;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:36:22
|
||||
|
|
||||
LL | reuse Trait::bar as foo;
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:42:30
|
||||
|
|
||||
LL | reuse super::fifth_mod::{bar as foo, foo as bar};
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:42:42
|
||||
|
|
||||
LL | reuse super::fifth_mod::{bar as foo, foo as bar};
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:47:27
|
||||
|
|
||||
LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:47:39
|
||||
|
|
||||
LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
|
||||
| ^^^
|
||||
|
||||
error: encountered a cycle during delegation signature resolution
|
||||
--> $DIR/recursive-delegation-errors.rs:47:51
|
||||
|
|
||||
LL | reuse GlobReuse::{foo as bar, bar as goo, goo as foo};
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
||||
68
tests/ui/delegation/recursive-delegation-pass.rs
Normal file
68
tests/ui/delegation/recursive-delegation-pass.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
//@ check-pass
|
||||
//@ edition:2018
|
||||
//@ aux-crate:recursive_delegation_aux=recursive-delegation-aux.rs
|
||||
|
||||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
mod first_mod {
|
||||
pub mod to_reuse {
|
||||
pub fn foo(x: usize) -> usize {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
|
||||
mod single_reuse {
|
||||
reuse crate::first_mod::to_reuse::foo;
|
||||
reuse foo as bar;
|
||||
reuse foo as bar1;
|
||||
reuse bar as goo;
|
||||
reuse goo as koo;
|
||||
reuse koo as too;
|
||||
}
|
||||
|
||||
mod glob_reuse {
|
||||
reuse super::to_reuse::{foo as bar, foo as bar1} { self }
|
||||
reuse super::glob_reuse::{bar as goo, goo as koo, koo as too} { self }
|
||||
}
|
||||
}
|
||||
|
||||
mod second_mod {
|
||||
trait T {
|
||||
fn foo(&self);
|
||||
reuse T::foo as bar;
|
||||
reuse T::bar as goo;
|
||||
reuse T::goo as poo;
|
||||
}
|
||||
|
||||
trait TGlob {
|
||||
fn xd(&self) -> &Self;
|
||||
fn foo1(&self);
|
||||
fn foo2(&self);
|
||||
fn foo3(&self);
|
||||
fn foo4(&self);
|
||||
|
||||
reuse TGlob::{foo1 as bar1, foo3 as bar3, bar1 as bar11, bar11 as bar111} { self.xd() }
|
||||
}
|
||||
}
|
||||
|
||||
mod third_mod {
|
||||
reuse crate::first_mod::to_reuse::foo {
|
||||
reuse foo as bar {
|
||||
reuse bar as goo {
|
||||
bar(123)
|
||||
}
|
||||
|
||||
goo(123)
|
||||
}
|
||||
|
||||
bar(123)
|
||||
}
|
||||
}
|
||||
|
||||
mod fourth_mod {
|
||||
reuse recursive_delegation_aux::goo as bar;
|
||||
reuse bar as foo;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -36,24 +36,15 @@ LL | reuse ToReuse::opaque_ret;
|
|||
| ^^^^^^^^^^
|
||||
= 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: recursive delegation is not supported yet
|
||||
--> $DIR/unsupported.rs:46:22
|
||||
|
|
||||
LL | pub reuse to_reuse2::foo;
|
||||
| --- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse1::foo;
|
||||
| ^^^
|
||||
|
||||
error[E0283]: type annotations needed
|
||||
--> $DIR/unsupported.rs:55:18
|
||||
--> $DIR/unsupported.rs:54:18
|
||||
|
|
||||
LL | reuse Trait::foo;
|
||||
| ^^^ cannot infer type
|
||||
|
|
||||
= note: cannot satisfy `_: effects::Trait`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0283, E0391.
|
||||
For more information about an error, try `rustc --explain E0283`.
|
||||
|
|
|
|||
|
|
@ -28,24 +28,15 @@ LL | reuse ToReuse::opaque_ret;
|
|||
= note: cycle used when computing implied outlives bounds for `<u16 as opaque::ToReuse>::opaque_ret::{anon_assoc#0}` (hack disabled = false)
|
||||
= 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: recursive delegation is not supported yet
|
||||
--> $DIR/unsupported.rs:46:22
|
||||
|
|
||||
LL | pub reuse to_reuse2::foo;
|
||||
| --- callee defined here
|
||||
...
|
||||
LL | reuse to_reuse1::foo;
|
||||
| ^^^
|
||||
|
||||
error[E0283]: type annotations needed
|
||||
--> $DIR/unsupported.rs:55:18
|
||||
--> $DIR/unsupported.rs:54:18
|
||||
|
|
||||
LL | reuse Trait::foo;
|
||||
| ^^^ cannot infer type
|
||||
|
|
||||
= note: cannot satisfy `_: effects::Trait`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0283, E0391.
|
||||
For more information about an error, try `rustc --explain E0283`.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ mod recursive {
|
|||
}
|
||||
|
||||
reuse to_reuse1::foo;
|
||||
//~^ ERROR recursive delegation is not supported yet
|
||||
}
|
||||
|
||||
mod effects {
|
||||
|
|
|
|||
19
tests/ui/eii/default/multiple-default-impls-same-name.rs
Normal file
19
tests/ui/eii/default/multiple-default-impls-same-name.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#![crate_type = "lib"]
|
||||
#![feature(extern_item_impls)]
|
||||
// `eii` expands to, among other things, `macro eii() {}`.
|
||||
// If we have two eiis named the same thing, we have a duplicate definition
|
||||
// for that macro. The compiler happily continues compiling on duplicate
|
||||
// definitions though, to emit as many diagnostics as possible.
|
||||
// However, in the case of eiis, this can break the assumption that every
|
||||
// eii has only one default implementation, since the default for both eiis will
|
||||
// name resolve to the same eii definiton (since the other definition was duplicate)
|
||||
// This test tests for the previously-ICE that occurred when this assumption
|
||||
// (of 1 default) was broken which was reported in #149982.
|
||||
|
||||
#[eii(eii1)]
|
||||
fn a() {}
|
||||
|
||||
#[eii(eii1)]
|
||||
//~^ ERROR the name `eii1` is defined multiple times
|
||||
fn a() {}
|
||||
//~^ ERROR the name `a` is defined multiple times
|
||||
25
tests/ui/eii/default/multiple-default-impls-same-name.stderr
Normal file
25
tests/ui/eii/default/multiple-default-impls-same-name.stderr
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
error[E0428]: the name `a` is defined multiple times
|
||||
--> $DIR/multiple-default-impls-same-name.rs:18:1
|
||||
|
|
||||
LL | fn a() {}
|
||||
| ------ previous definition of the value `a` here
|
||||
...
|
||||
LL | fn a() {}
|
||||
| ^^^^^^ `a` redefined here
|
||||
|
|
||||
= note: `a` must be defined only once in the value namespace of this module
|
||||
|
||||
error[E0428]: the name `eii1` is defined multiple times
|
||||
--> $DIR/multiple-default-impls-same-name.rs:16:1
|
||||
|
|
||||
LL | #[eii(eii1)]
|
||||
| ------------ previous definition of the macro `eii1` here
|
||||
...
|
||||
LL | #[eii(eii1)]
|
||||
| ^^^^^^^^^^^^ `eii1` redefined here
|
||||
|
|
||||
= note: `eii1` must be defined only once in the macro namespace of this module
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0428`.
|
||||
18
tests/ui/eii/default/multiple-default-impls.rs
Normal file
18
tests/ui/eii/default/multiple-default-impls.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#![crate_type = "lib"]
|
||||
#![feature(extern_item_impls)]
|
||||
// `eii` expands to, among other things, `macro eii() {}`.
|
||||
// If we have two eiis named the same thing, we have a duplicate definition
|
||||
// for that macro. The compiler happily continues compiling on duplicate
|
||||
// definitions though, to emit as many diagnostics as possible.
|
||||
// However, in the case of eiis, this can break the assumption that every
|
||||
// eii has only one default implementation, since the default for both eiis will
|
||||
// name resolve to the same eii definiton (since the other definition was duplicate)
|
||||
// This test tests for the previously-ICE that occurred when this assumption
|
||||
// (of 1 default) was broken which was reported in #149982.
|
||||
|
||||
#[eii(eii1)]
|
||||
fn a() {}
|
||||
|
||||
#[eii(eii1)]
|
||||
//~^ ERROR the name `eii1` is defined multiple times
|
||||
fn b() {}
|
||||
14
tests/ui/eii/default/multiple-default-impls.stderr
Normal file
14
tests/ui/eii/default/multiple-default-impls.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
error[E0428]: the name `eii1` is defined multiple times
|
||||
--> $DIR/multiple-default-impls.rs:16:1
|
||||
|
|
||||
LL | #[eii(eii1)]
|
||||
| ------------ previous definition of the macro `eii1` here
|
||||
...
|
||||
LL | #[eii(eii1)]
|
||||
| ^^^^^^^^^^^^ `eii1` redefined here
|
||||
|
|
||||
= note: `eii1` must be defined only once in the macro namespace of this module
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0428`.
|
||||
|
|
@ -47,6 +47,89 @@ fn arm_rhs_expr_3() -> i32 {
|
|||
}
|
||||
}
|
||||
|
||||
fn expand_to_statements() -> i32 {
|
||||
cfg_select! {
|
||||
true => {
|
||||
let a = 1;
|
||||
a + 1
|
||||
}
|
||||
false => {
|
||||
let b = 2;
|
||||
b + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ExpandToType = cfg_select! {
|
||||
unix => u32,
|
||||
_ => i32,
|
||||
};
|
||||
|
||||
fn expand_to_pattern(x: Option<i32>) -> bool {
|
||||
match x {
|
||||
(cfg_select! {
|
||||
unix => Some(n),
|
||||
_ => None,
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
true => {
|
||||
fn foo() {}
|
||||
}
|
||||
_ => {
|
||||
fn bar() {}
|
||||
}
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
cfg_select! {
|
||||
true => {
|
||||
fn foo() {}
|
||||
}
|
||||
_ => {
|
||||
fn bar() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait T {
|
||||
cfg_select! {
|
||||
true => {
|
||||
fn a();
|
||||
}
|
||||
_ => {
|
||||
fn b();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl T for S {
|
||||
cfg_select! {
|
||||
true => {
|
||||
fn a() {}
|
||||
}
|
||||
_ => {
|
||||
fn b() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
cfg_select! {
|
||||
true => {
|
||||
fn puts(s: *const i8) -> i32;
|
||||
}
|
||||
_ => {
|
||||
fn printf(fmt: *const i8, ...) -> i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
_ => {}
|
||||
true => {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
warning: unreachable predicate
|
||||
--> $DIR/cfg_select.rs:52:5
|
||||
--> $DIR/cfg_select.rs:135:5
|
||||
|
|
||||
LL | _ => {}
|
||||
| - always matches
|
||||
|
|
@ -7,7 +7,7 @@ LL | true => {}
|
|||
| ^^^^ this predicate is never reached
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:56:1
|
||||
--> $DIR/cfg_select.rs:139:1
|
||||
|
|
||||
LL | / cfg_select! {
|
||||
LL | |
|
||||
|
|
@ -16,55 +16,55 @@ LL | | }
|
|||
| |_^
|
||||
|
||||
error: none of the predicates in this `cfg_select` evaluated to true
|
||||
--> $DIR/cfg_select.rs:61:1
|
||||
--> $DIR/cfg_select.rs:144:1
|
||||
|
|
||||
LL | cfg_select! {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
|
||||
--> $DIR/cfg_select.rs:65:5
|
||||
--> $DIR/cfg_select.rs:148:5
|
||||
|
|
||||
LL | => {}
|
||||
| ^^
|
||||
|
||||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
|
||||
--> $DIR/cfg_select.rs:70:5
|
||||
--> $DIR/cfg_select.rs:153:5
|
||||
|
|
||||
LL | () => {}
|
||||
| ^^ expressions are not allowed here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:75:5
|
||||
--> $DIR/cfg_select.rs:158:5
|
||||
|
|
||||
LL | "str" => {}
|
||||
| ^^^^^ expected a valid identifier here
|
||||
|
||||
error[E0539]: malformed `cfg_select` macro input
|
||||
--> $DIR/cfg_select.rs:80:5
|
||||
--> $DIR/cfg_select.rs:163:5
|
||||
|
|
||||
LL | a::b => {}
|
||||
| ^^^^ expected a valid identifier here
|
||||
|
||||
error[E0537]: invalid predicate `a`
|
||||
--> $DIR/cfg_select.rs:85:5
|
||||
--> $DIR/cfg_select.rs:168:5
|
||||
|
|
||||
LL | a() => {}
|
||||
| ^^^
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
|
||||
--> $DIR/cfg_select.rs:90:7
|
||||
--> $DIR/cfg_select.rs:173:7
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
error: expected one of `(`, `::`, `=>`, or `=`, found `!`
|
||||
--> $DIR/cfg_select.rs:96:8
|
||||
--> $DIR/cfg_select.rs:179:8
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^ expected one of `(`, `::`, `=>`, or `=`
|
||||
|
||||
warning: unexpected `cfg` condition name: `a`
|
||||
--> $DIR/cfg_select.rs:90:5
|
||||
--> $DIR/cfg_select.rs:173:5
|
||||
|
|
||||
LL | a + 1 => {}
|
||||
| ^ help: found config with similar value: `target_feature = "a"`
|
||||
|
|
@ -75,7 +75,7 @@ LL | a + 1 => {}
|
|||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
|
||||
warning: unexpected `cfg` condition name: `cfg`
|
||||
--> $DIR/cfg_select.rs:96:5
|
||||
--> $DIR/cfg_select.rs:179:5
|
||||
|
|
||||
LL | cfg!() => {}
|
||||
| ^^^
|
||||
|
|
|
|||
18
tests/ui/macros/cfg_select_parse_error.rs
Normal file
18
tests/ui/macros/cfg_select_parse_error.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#![feature(cfg_select)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Check that parse errors in arms that are not selected are still reported.
|
||||
|
||||
fn print() {
|
||||
println!(cfg_select! {
|
||||
false => { 1 ++ 2 }
|
||||
//~^ ERROR Rust has no postfix increment operator
|
||||
_ => { "not unix" }
|
||||
});
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
false => { fn foo() { 1 +++ 2 } }
|
||||
//~^ ERROR Rust has no postfix increment operator
|
||||
_ => {}
|
||||
}
|
||||
26
tests/ui/macros/cfg_select_parse_error.stderr
Normal file
26
tests/ui/macros/cfg_select_parse_error.stderr
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
error: Rust has no postfix increment operator
|
||||
--> $DIR/cfg_select_parse_error.rs:8:22
|
||||
|
|
||||
LL | false => { 1 ++ 2 }
|
||||
| ^^ not a valid postfix operator
|
||||
|
|
||||
help: use `+= 1` instead
|
||||
|
|
||||
LL - false => { 1 ++ 2 }
|
||||
LL + false => { { let tmp = 1 ; 1 += 1; tmp } 2 }
|
||||
|
|
||||
|
||||
error: Rust has no postfix increment operator
|
||||
--> $DIR/cfg_select_parse_error.rs:15:29
|
||||
|
|
||||
LL | false => { fn foo() { 1 +++ 2 } }
|
||||
| ^^ not a valid postfix operator
|
||||
|
|
||||
help: use `+= 1` instead
|
||||
|
|
||||
LL - false => { fn foo() { 1 +++ 2 } }
|
||||
LL + false => { fn foo() { { let tmp = 1 ; 1 += 1; tmp }+ 2 } }
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -4,10 +4,16 @@ error[E0425]: cannot find value `a` in this scope
|
|||
LL | [a.., a] => {}
|
||||
| ^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `a`, use the at operator
|
||||
|
|
||||
LL | [a @ .., a] => {}
|
||||
| +
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - [a.., a] => {}
|
||||
LL + [std::ops::RangeFrom { start: a }, a] => {}
|
||||
|
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,16 @@ error[E0425]: cannot find value `rest` in this scope
|
|||
LL | [1, rest..] => println!("{rest}"),
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `rest`, use the at operator
|
||||
|
|
||||
LL | [1, rest @ ..] => println!("{rest}"),
|
||||
| +
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - [1, rest..] => println!("{rest}"),
|
||||
LL + [1, std::ops::RangeFrom { start: rest }] => println!("{rest}"),
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `rest` in this scope
|
||||
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:3:35
|
||||
|
|
@ -33,11 +39,17 @@ error[E0425]: cannot find value `tail` in this scope
|
|||
LL | [_, ..tail] => println!("{tail}"),
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `tail`, use the at operator
|
||||
|
|
||||
LL - [_, ..tail] => println!("{tail}"),
|
||||
LL + [_, tail @ ..] => println!("{tail}"),
|
||||
|
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - [_, ..tail] => println!("{tail}"),
|
||||
LL + [_, std::ops::RangeTo { end: tail }] => println!("{tail}"),
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `tail` in this scope
|
||||
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:11:35
|
||||
|
|
@ -51,11 +63,17 @@ error[E0425]: cannot find value `tail` in this scope
|
|||
LL | [_, ...tail] => println!("{tail}"),
|
||||
| ^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `tail`, use the at operator
|
||||
|
|
||||
LL - [_, ...tail] => println!("{tail}"),
|
||||
LL + [_, tail @ ..] => println!("{tail}"),
|
||||
|
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - [_, ...tail] => println!("{tail}"),
|
||||
LL + [_, std::ops::RangeToInclusive { end: tail }] => println!("{tail}"),
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `tail` in this scope
|
||||
--> $DIR/range-pattern-meant-to-be-slice-rest-pattern.rs:17:36
|
||||
|
|
|
|||
40
tests/ui/resolve/suggest-range-struct-destructuring.rs
Normal file
40
tests/ui/resolve/suggest-range-struct-destructuring.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use std::ops::{Range, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};
|
||||
|
||||
fn test_range(r: Range<u32>) {
|
||||
let start..end = r;
|
||||
//~^ ERROR cannot find value `start`
|
||||
//~| ERROR cannot find value `end`
|
||||
}
|
||||
|
||||
fn test_inclusive(r: RangeInclusive<u32>) {
|
||||
let start..=end = r;
|
||||
//~^ ERROR cannot find value `start`
|
||||
//~| ERROR cannot find value `end`
|
||||
}
|
||||
|
||||
fn test_from(r: RangeFrom<u32>) {
|
||||
let start.. = r;
|
||||
//~^ ERROR cannot find value `start`
|
||||
}
|
||||
|
||||
fn test_to(r: RangeTo<u32>) {
|
||||
let ..end = r;
|
||||
//~^ ERROR cannot find value `end`
|
||||
}
|
||||
|
||||
fn test_to_inclusive(r: RangeToInclusive<u32>) {
|
||||
let ..=end = r;
|
||||
//~^ ERROR cannot find value `end`
|
||||
}
|
||||
|
||||
// Case 6: Complex Path (Keep this! It works!)
|
||||
mod my {
|
||||
// We don't define MISSING here to trigger the error
|
||||
}
|
||||
fn test_path(r: Range<u32>) {
|
||||
let my::MISSING..end = r;
|
||||
//~^ ERROR cannot find value `MISSING`
|
||||
//~| ERROR cannot find value `end`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
127
tests/ui/resolve/suggest-range-struct-destructuring.stderr
Normal file
127
tests/ui/resolve/suggest-range-struct-destructuring.stderr
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
error[E0425]: cannot find value `start` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:4:9
|
||||
|
|
||||
LL | let start..end = r;
|
||||
| ^^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let start..end = r;
|
||||
LL + let Range { start, end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `end` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:4:16
|
||||
|
|
||||
LL | let start..end = r;
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let start..end = r;
|
||||
LL + let Range { start, end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `start` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:10:9
|
||||
|
|
||||
LL | let start..=end = r;
|
||||
| ^^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let start..=end = r;
|
||||
LL + let RangeInclusive { start, end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `end` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:10:17
|
||||
|
|
||||
LL | let start..=end = r;
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let start..=end = r;
|
||||
LL + let RangeInclusive { start, end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `start` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:16:9
|
||||
|
|
||||
LL | let start.. = r;
|
||||
| ^^^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `start`, use the at operator
|
||||
|
|
||||
LL | let start @ .. = r;
|
||||
| +
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let start.. = r;
|
||||
LL + let RangeFrom { start } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `end` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:21:11
|
||||
|
|
||||
LL | let ..end = r;
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `end`, use the at operator
|
||||
|
|
||||
LL - let ..end = r;
|
||||
LL + let end @ .. = r;
|
||||
|
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let ..end = r;
|
||||
LL + let RangeTo { end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `end` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:26:12
|
||||
|
|
||||
LL | let ..=end = r;
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `end`, use the at operator
|
||||
|
|
||||
LL - let ..=end = r;
|
||||
LL + let end @ .. = r;
|
||||
|
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let ..=end = r;
|
||||
LL + let RangeToInclusive { end } = r;
|
||||
|
|
||||
|
||||
error[E0425]: cannot find value `MISSING` in module `my`
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:35:13
|
||||
|
|
||||
LL | let my::MISSING..end = r;
|
||||
| ^^^^^^^ not found in `my`
|
||||
|
||||
error[E0425]: cannot find value `end` in this scope
|
||||
--> $DIR/suggest-range-struct-destructuring.rs:35:22
|
||||
|
|
||||
LL | let my::MISSING..end = r;
|
||||
| ^^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let my::MISSING..end = r;
|
||||
LL + let Range { start: my::MISSING, end } = r;
|
||||
|
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0425`.
|
||||
|
|
@ -4,10 +4,16 @@ error[E0425]: cannot find value `_y` in this scope
|
|||
LL | let [_y..] = [Box::new(1), Box::new(2)];
|
||||
| ^^ not found in this scope
|
||||
|
|
||||
= note: range patterns match against the start and end of a range; to bind the components, use a struct pattern
|
||||
help: if you meant to collect the rest of the slice in `_y`, use the at operator
|
||||
|
|
||||
LL | let [_y @ ..] = [Box::new(1), Box::new(2)];
|
||||
| +
|
||||
help: if you meant to destructure a range use a struct pattern
|
||||
|
|
||||
LL - let [_y..] = [Box::new(1), Box::new(2)];
|
||||
LL + let [std::ops::RangeFrom { start: _y }] = [Box::new(1), Box::new(2)];
|
||||
|
|
||||
|
||||
error[E0658]: `X..` patterns in slices are experimental
|
||||
--> $DIR/issue-105946.rs:7:10
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue