Auto merge of #126134 - matthiaskrgr:rollup-vzlegsc, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #124012 (Stabilize `binary_heap_as_slice`) - #124214 (Parse unsafe attributes) - #125572 (Detect pub structs never constructed and unused associated constants) - #125781 (prefer `compile::stream_cargo` for building tools) - #126030 (Update `./x fmt` command in library/std/src/sys/pal/windows/c/README.md) - #126047 (Simplify the rayon calls in the installer) - #126052 (More `rustc_parse` cleanups) - #126077 (Revert "Use the HIR instead of mir_keys for determining whether something will have a MIR body.") - #126089 (Stabilize Option::take_if) - #126112 (Clean up source root in run-make tests) - #126119 (Improve docs for using custom paths with `--emit`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
804421dff5
89 changed files with 745 additions and 234 deletions
|
@ -488,6 +488,7 @@ pub struct Crate {
|
|||
/// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct MetaItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub kind: MetaItemKind,
|
||||
pub span: Span,
|
||||
|
@ -2823,7 +2824,12 @@ pub struct NormalAttr {
|
|||
impl NormalAttr {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
Self {
|
||||
item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None },
|
||||
item: AttrItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(ident),
|
||||
args: AttrArgs::Empty,
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
}
|
||||
}
|
||||
|
@ -2831,6 +2837,7 @@ impl NormalAttr {
|
|||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct AttrItem {
|
||||
pub unsafety: Safety,
|
||||
pub path: Path,
|
||||
pub args: AttrArgs,
|
||||
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Functions dealing with attributes and meta items.
|
||||
|
||||
use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
|
||||
use crate::ast::{
|
||||
AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety,
|
||||
};
|
||||
use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
|
||||
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
|
||||
use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
|
||||
|
@ -238,7 +240,12 @@ impl AttrItem {
|
|||
}
|
||||
|
||||
pub fn meta(&self, span: Span) -> Option<MetaItem> {
|
||||
Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span })
|
||||
Some(MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: self.path.clone(),
|
||||
kind: self.meta_kind()?,
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn meta_kind(&self) -> Option<MetaItemKind> {
|
||||
|
@ -371,7 +378,10 @@ impl MetaItem {
|
|||
_ => path.span.hi(),
|
||||
};
|
||||
let span = path.span.with_hi(hi);
|
||||
Some(MetaItem { path, kind, span })
|
||||
// FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`,
|
||||
// but as a parenthesized list. This (and likely `MetaItem`) should be changed in
|
||||
// such a way that builtin macros don't accept extraneous `unsafe()`.
|
||||
Some(MetaItem { unsafety: Safety::Default, path, kind, span })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,11 +565,12 @@ pub fn mk_doc_comment(
|
|||
pub fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
path: Path,
|
||||
args: AttrArgs,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span)
|
||||
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_from_item(
|
||||
|
@ -577,15 +588,22 @@ pub fn mk_attr_from_item(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute {
|
||||
pub fn mk_attr_word(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
) -> Attribute {
|
||||
let path = Path::from_ident(Ident::new(name, span));
|
||||
let args = AttrArgs::Empty;
|
||||
mk_attr(g, style, path, args, span)
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_nested_word(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
outer: Symbol,
|
||||
inner: Symbol,
|
||||
span: Span,
|
||||
|
@ -601,12 +619,13 @@ pub fn mk_attr_nested_word(
|
|||
delim: Delimiter::Parenthesis,
|
||||
tokens: inner_tokens,
|
||||
});
|
||||
mk_attr(g, style, path, attr_args, span)
|
||||
mk_attr(g, style, unsafety, path, attr_args, span)
|
||||
}
|
||||
|
||||
pub fn mk_attr_name_value_str(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
name: Symbol,
|
||||
val: Symbol,
|
||||
span: Span,
|
||||
|
@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str(
|
|||
});
|
||||
let path = Path::from_ident(Ident::new(name, span));
|
||||
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr));
|
||||
mk_attr(g, style, path, args, span)
|
||||
mk_attr(g, style, unsafety, path, args, span)
|
||||
}
|
||||
|
||||
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
|
||||
|
|
|
@ -647,8 +647,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
|
|||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } =
|
||||
&mut **normal;
|
||||
let NormalAttr {
|
||||
item: AttrItem { unsafety: _, path, args, tokens },
|
||||
tokens: attr_tokens,
|
||||
} = &mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(args, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
|
@ -678,7 +680,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T
|
|||
}
|
||||
|
||||
fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) {
|
||||
let MetaItem { path: _, kind, span } = mi;
|
||||
let MetaItem { unsafety: _, path: _, kind, span } = mi;
|
||||
match kind {
|
||||
MetaItemKind::Word => {}
|
||||
MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)),
|
||||
|
@ -840,7 +842,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
|
|||
token::NtTy(ty) => vis.visit_ty(ty),
|
||||
token::NtLiteral(expr) => vis.visit_expr(expr),
|
||||
token::NtMeta(item) => {
|
||||
let AttrItem { path, args, tokens } = item.deref_mut();
|
||||
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(args, vis);
|
||||
visit_lazy_tts(tokens, vis);
|
||||
|
|
|
@ -1805,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let attr = attr::mk_attr_nested_word(
|
||||
&self.tcx.sess.psess.attr_id_generator,
|
||||
AttrStyle::Outer,
|
||||
Safety::Default,
|
||||
sym::allow,
|
||||
sym::unreachable_code,
|
||||
self.lower_span(span),
|
||||
|
|
|
@ -905,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let kind = match attr.kind {
|
||||
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
|
||||
item: AttrItem {
|
||||
unsafety: normal.item.unsafety,
|
||||
path: normal.item.path.clone(),
|
||||
args: self.lower_attr_args(&normal.item.args),
|
||||
tokens: None,
|
||||
|
|
|
@ -561,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To
|
|||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety};
|
||||
use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
|
||||
use rustc_ast::{GenericArg, GenericBound, SelfKind};
|
||||
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
|
||||
|
@ -249,6 +249,7 @@ pub fn print_crate<'a>(
|
|||
let fake_attr = attr::mk_attr_nested_word(
|
||||
g,
|
||||
ast::AttrStyle::Inner,
|
||||
Safety::Default,
|
||||
sym::feature,
|
||||
sym::prelude_import,
|
||||
DUMMY_SP,
|
||||
|
@ -259,7 +260,13 @@ pub fn print_crate<'a>(
|
|||
// root, so this is not needed, and actually breaks things.
|
||||
if edition.is_rust_2015() {
|
||||
// `#![no_std]`
|
||||
let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP);
|
||||
let fake_attr = attr::mk_attr_word(
|
||||
g,
|
||||
ast::AttrStyle::Inner,
|
||||
Safety::Default,
|
||||
sym::no_std,
|
||||
DUMMY_SP,
|
||||
);
|
||||
s.print_attribute(&fake_attr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
|
|||
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
|
||||
.suggestion = remove the value
|
||||
|
||||
builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)`
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
|
||||
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
|
||||
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
|
||||
.custom = use `std::env::var({$var_expr})` to read the variable at run time
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
|||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
|
@ -33,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
|||
krate.attrs.push(mk_attr(
|
||||
&psess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
unsafety,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
|
|||
use crate::errors;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
|
||||
use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind};
|
||||
use rustc_expand::base::{
|
||||
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
|
||||
};
|
||||
|
@ -60,6 +60,7 @@ impl MultiItemModifier for Expander {
|
|||
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
|
||||
// paths.
|
||||
report_path_args(sess, meta);
|
||||
report_unsafe_args(sess, meta);
|
||||
meta.path.clone()
|
||||
})
|
||||
.map(|path| DeriveResolution {
|
||||
|
@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) {
|
||||
match meta.unsafety {
|
||||
Safety::Unsafe(span) => {
|
||||
sess.dcx().emit_err(errors::DeriveUnsafePath { span });
|
||||
}
|
||||
Safety::Default => {}
|
||||
Safety::Safe(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -295,6 +295,13 @@ pub(crate) struct DerivePathArgsValue {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_derive_unsafe_path)]
|
||||
pub(crate) struct DeriveUnsafePath {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_no_default_variant)]
|
||||
#[help]
|
||||
|
|
|
@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
|
|||
let allow_dead_code = attr::mk_attr_nested_word(
|
||||
&self.sess.psess.attr_id_generator,
|
||||
ast::AttrStyle::Outer,
|
||||
ast::Safety::Default,
|
||||
sym::allow,
|
||||
sym::dead_code,
|
||||
self.def_site,
|
||||
|
|
|
@ -666,7 +666,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
// Builds `#[name]`.
|
||||
pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
|
||||
let g = &self.sess.psess.attr_id_generator;
|
||||
attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span)
|
||||
attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span)
|
||||
}
|
||||
|
||||
// Builds `#[name = val]`.
|
||||
|
@ -674,12 +674,26 @@ impl<'a> ExtCtxt<'a> {
|
|||
// Note: `span` is used for both the identifier and the value.
|
||||
pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
|
||||
let g = &self.sess.psess.attr_id_generator;
|
||||
attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span)
|
||||
attr::mk_attr_name_value_str(
|
||||
g,
|
||||
ast::AttrStyle::Outer,
|
||||
ast::Safety::Default,
|
||||
name,
|
||||
val,
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
// Builds `#[outer(inner)]`.
|
||||
pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute {
|
||||
let g = &self.sess.psess.attr_id_generator;
|
||||
attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span)
|
||||
attr::mk_attr_nested_word(
|
||||
g,
|
||||
ast::AttrStyle::Outer,
|
||||
ast::Safety::Default,
|
||||
outer,
|
||||
inner,
|
||||
span,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -778,7 +778,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
if let SyntaxExtensionKind::Derive(..) = ext {
|
||||
self.gate_proc_macro_input(&item);
|
||||
}
|
||||
let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
|
||||
// The `MetaItem` representing the trait to derive can't
|
||||
// have an unsafe around it (as of now).
|
||||
let meta = ast::MetaItem {
|
||||
unsafety: ast::Safety::Default,
|
||||
kind: MetaItemKind::Word,
|
||||
span,
|
||||
path,
|
||||
};
|
||||
let items = match expander.expand(self.cx, span, &meta, item, is_const) {
|
||||
ExpandResult::Ready(items) => items,
|
||||
ExpandResult::Retry(item) => {
|
||||
|
|
|
@ -59,6 +59,16 @@ pub enum AttributeType {
|
|||
CrateLevel,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||
pub enum AttributeSafety {
|
||||
/// Normal attribute that does not need `#[unsafe(...)]`
|
||||
Normal,
|
||||
|
||||
/// Unsafe attribute that requires safety obligations
|
||||
/// to be discharged
|
||||
Unsafe,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum AttributeGate {
|
||||
/// Is gated by a given feature gate, reason
|
||||
|
@ -172,11 +182,23 @@ macro_rules! template {
|
|||
}
|
||||
|
||||
macro_rules! ungated {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
gate: Ungated,
|
||||
duplicates: $duplicates,
|
||||
|
@ -185,11 +207,34 @@ macro_rules! ungated {
|
|||
}
|
||||
|
||||
macro_rules! gated {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
|
||||
}
|
||||
};
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Unsafe,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
|
||||
|
@ -200,6 +245,7 @@ macro_rules! gated {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
|
||||
|
@ -228,6 +274,7 @@ macro_rules! rustc_attr {
|
|||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
type_: $typ,
|
||||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
|
||||
|
@ -258,6 +305,7 @@ pub struct BuiltinAttribute {
|
|||
/// Otherwise, it can only be used in the local crate.
|
||||
pub encode_cross_crate: EncodeCrossCrate,
|
||||
pub type_: AttributeType,
|
||||
pub safety: AttributeSafety,
|
||||
pub template: AttributeTemplate,
|
||||
pub duplicates: AttributeDuplicates,
|
||||
pub gate: AttributeGate,
|
||||
|
@ -375,9 +423,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
|
||||
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
|
||||
ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
|
||||
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
|
||||
|
||||
|
@ -486,11 +534,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
|
||||
gated!(
|
||||
ffi_pure, Normal, template!(Word), WarnFollowing,
|
||||
unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, experimental!(ffi_pure)
|
||||
),
|
||||
gated!(
|
||||
ffi_const, Normal, template!(Word), WarnFollowing,
|
||||
unsafe ffi_const, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, experimental!(ffi_const)
|
||||
),
|
||||
gated!(
|
||||
|
@ -850,6 +898,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
|
||||
encode_cross_crate: EncodeCrossCrate::Yes,
|
||||
type_: Normal,
|
||||
safety: AttributeSafety::Normal,
|
||||
template: template!(NameValueStr: "name"),
|
||||
duplicates: ErrorFollowing,
|
||||
gate: Gated(
|
||||
|
@ -1096,6 +1145,10 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn is_unsafe_attr(name: Symbol) -> bool {
|
||||
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe)
|
||||
}
|
||||
|
||||
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
|
||||
LazyLock::new(|| {
|
||||
let mut map = FxHashMap::default();
|
||||
|
|
|
@ -123,8 +123,8 @@ pub use accepted::ACCEPTED_FEATURES;
|
|||
pub use builtin_attrs::AttributeDuplicates;
|
||||
pub use builtin_attrs::{
|
||||
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
|
||||
is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute,
|
||||
GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||
is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
|
||||
BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
|
||||
};
|
||||
pub use removed::REMOVED_FEATURES;
|
||||
pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
|
||||
|
|
|
@ -620,6 +620,8 @@ declare_features! (
|
|||
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
|
||||
/// Allows unnamed fields of struct and union type
|
||||
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
|
||||
/// Allows unsafe attributes.
|
||||
(unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)),
|
||||
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
|
||||
(unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
|
||||
/// Allows unsized fn parameters.
|
||||
|
|
|
@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
|||
}
|
||||
|
||||
fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
tcx.hir().maybe_body_owned_by(def_id).is_some()
|
||||
tcx.mir_keys(()).contains(&def_id)
|
||||
}
|
||||
|
||||
/// Finds the full set of `DefId`s within the current crate that have
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_ast as ast;
|
|||
use rustc_ast::attr;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
use rustc_errors::{codes::*, Diag, PResult};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
use rustc_span::{sym, symbol::kw, BytePos, Span};
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -252,9 +252,23 @@ impl<'a> Parser<'a> {
|
|||
maybe_whole!(self, NtMeta, |attr| attr.into_inner());
|
||||
|
||||
let do_parse = |this: &mut Self| {
|
||||
let is_unsafe = this.eat_keyword(kw::Unsafe);
|
||||
let unsafety = if is_unsafe {
|
||||
let unsafe_span = this.prev_token.span;
|
||||
this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
|
||||
this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
|
||||
|
||||
ast::Safety::Unsafe(unsafe_span)
|
||||
} else {
|
||||
ast::Safety::Default
|
||||
};
|
||||
|
||||
let path = this.parse_path(PathStyle::Mod)?;
|
||||
let args = this.parse_attr_args()?;
|
||||
Ok(ast::AttrItem { path, args, tokens: None })
|
||||
if is_unsafe {
|
||||
this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
||||
}
|
||||
Ok(ast::AttrItem { unsafety, path, args, tokens: None })
|
||||
};
|
||||
// Attr items don't have attributes
|
||||
if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
|
||||
|
@ -375,10 +389,25 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
let lo = self.token.span;
|
||||
let is_unsafe = self.eat_keyword(kw::Unsafe);
|
||||
let unsafety = if is_unsafe {
|
||||
let unsafe_span = self.prev_token.span;
|
||||
self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
|
||||
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
|
||||
|
||||
ast::Safety::Unsafe(unsafe_span)
|
||||
} else {
|
||||
ast::Safety::Default
|
||||
};
|
||||
|
||||
let path = self.parse_path(PathStyle::Mod)?;
|
||||
let kind = self.parse_meta_item_kind()?;
|
||||
if is_unsafe {
|
||||
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
|
||||
}
|
||||
let span = lo.to(self.prev_token.span);
|
||||
Ok(ast::MetaItem { path, kind, span })
|
||||
|
||||
Ok(ast::MetaItem { unsafety, path, kind, span })
|
||||
}
|
||||
|
||||
pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
|
||||
|
|
|
@ -130,14 +130,14 @@ pub enum AttemptLocalParseRecovery {
|
|||
}
|
||||
|
||||
impl AttemptLocalParseRecovery {
|
||||
pub fn yes(&self) -> bool {
|
||||
pub(super) fn yes(&self) -> bool {
|
||||
match self {
|
||||
AttemptLocalParseRecovery::Yes => true,
|
||||
AttemptLocalParseRecovery::No => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no(&self) -> bool {
|
||||
pub(super) fn no(&self) -> bool {
|
||||
match self {
|
||||
AttemptLocalParseRecovery::Yes => false,
|
||||
AttemptLocalParseRecovery::No => true,
|
||||
|
@ -891,7 +891,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn maybe_suggest_struct_literal(
|
||||
pub(super) fn maybe_suggest_struct_literal(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
s: BlockCheckMode,
|
||||
|
@ -2459,7 +2459,7 @@ impl<'a> Parser<'a> {
|
|||
/// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this
|
||||
/// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
|
||||
/// like the user has forgotten them.
|
||||
pub fn handle_ambiguous_unbraced_const_arg(
|
||||
pub(super) fn handle_ambiguous_unbraced_const_arg(
|
||||
&mut self,
|
||||
args: &mut ThinVec<AngleBracketedArg>,
|
||||
) -> PResult<'a, bool> {
|
||||
|
@ -2500,7 +2500,7 @@ impl<'a> Parser<'a> {
|
|||
/// - Single-segment paths (i.e. standalone generic const parameters).
|
||||
/// All other expressions that can be parsed will emit an error suggesting the expression be
|
||||
/// wrapped in braces.
|
||||
pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
|
||||
pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
|
||||
let start = self.token.span;
|
||||
let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| {
|
||||
err.span_label(
|
||||
|
@ -2559,7 +2559,7 @@ impl<'a> Parser<'a> {
|
|||
Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
|
||||
}
|
||||
|
||||
pub fn recover_const_param_declaration(
|
||||
pub(super) fn recover_const_param_declaration(
|
||||
&mut self,
|
||||
ty_generics: Option<&Generics>,
|
||||
) -> PResult<'a, Option<GenericArg>> {
|
||||
|
@ -2589,7 +2589,11 @@ impl<'a> Parser<'a> {
|
|||
/// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest
|
||||
/// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
|
||||
/// if we think that the resulting expression would be well formed.
|
||||
pub fn recover_const_arg(&mut self, start: Span, mut err: Diag<'a>) -> PResult<'a, GenericArg> {
|
||||
pub(super) fn recover_const_arg(
|
||||
&mut self,
|
||||
start: Span,
|
||||
mut err: Diag<'a>,
|
||||
) -> PResult<'a, GenericArg> {
|
||||
let is_op_or_dot = AssocOp::from_token(&self.token)
|
||||
.and_then(|op| {
|
||||
if let AssocOp::Greater
|
||||
|
@ -2690,7 +2694,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Creates a dummy const argument, and reports that the expression must be enclosed in braces
|
||||
pub fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg {
|
||||
pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg {
|
||||
err.multipart_suggestion(
|
||||
"expressions must be enclosed in braces to be used as const generic \
|
||||
arguments",
|
||||
|
@ -2961,7 +2965,7 @@ impl<'a> Parser<'a> {
|
|||
/// * `=====`
|
||||
/// * `<<<<<`
|
||||
///
|
||||
pub fn is_vcs_conflict_marker(
|
||||
pub(super) fn is_vcs_conflict_marker(
|
||||
&mut self,
|
||||
long_kind: &TokenKind,
|
||||
short_kind: &TokenKind,
|
||||
|
@ -2981,14 +2985,14 @@ impl<'a> Parser<'a> {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn recover_vcs_conflict_marker(&mut self) {
|
||||
pub(super) fn recover_vcs_conflict_marker(&mut self) {
|
||||
if let Err(err) = self.err_vcs_conflict_marker() {
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> {
|
||||
pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> {
|
||||
let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt)
|
||||
else {
|
||||
return Ok(());
|
||||
|
|
|
@ -431,7 +431,7 @@ impl<'a> Parser<'a> {
|
|||
/// The method does not advance the current token.
|
||||
///
|
||||
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
|
||||
pub fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
|
||||
pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
|
||||
let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
|
||||
// When parsing const expressions, stop parsing when encountering `>`.
|
||||
(
|
||||
|
@ -1006,7 +1006,11 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
|
||||
pub(super) fn parse_dot_suffix_expr(
|
||||
&mut self,
|
||||
lo: Span,
|
||||
base: P<Expr>,
|
||||
) -> PResult<'a, P<Expr>> {
|
||||
// At this point we've consumed something like `expr.` and `self.token` holds the token
|
||||
// after the dot.
|
||||
match self.token.uninterpolate().kind {
|
||||
|
|
|
@ -2265,7 +2265,7 @@ pub(crate) struct FnParseMode {
|
|||
/// to true.
|
||||
/// * The span is from Edition 2015. In particular, you can get a
|
||||
/// 2015 span inside a 2021 crate using macros.
|
||||
pub req_name: ReqName,
|
||||
pub(super) req_name: ReqName,
|
||||
/// If this flag is set to `true`, then plain, semicolon-terminated function
|
||||
/// prototypes are not allowed here.
|
||||
///
|
||||
|
@ -2284,7 +2284,7 @@ pub(crate) struct FnParseMode {
|
|||
/// This field should only be set to false if the item is inside of a trait
|
||||
/// definition or extern block. Within an impl block or a module, it should
|
||||
/// always be set to true.
|
||||
pub req_body: bool,
|
||||
pub(super) req_body: bool,
|
||||
}
|
||||
|
||||
/// Parsing of functions and methods.
|
||||
|
|
|
@ -11,14 +11,13 @@ mod stmt;
|
|||
mod ty;
|
||||
|
||||
use crate::lexer::UnmatchedDelim;
|
||||
pub use attr_wrapper::AttrWrapper;
|
||||
use attr_wrapper::AttrWrapper;
|
||||
pub use diagnostics::AttemptLocalParseRecovery;
|
||||
pub(crate) use expr::ForbiddenLetReason;
|
||||
pub(crate) use item::FnParseMode;
|
||||
pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
||||
pub use path::PathStyle;
|
||||
use path::PathStyle;
|
||||
|
||||
use core::fmt;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
|
||||
|
@ -37,7 +36,7 @@ use rustc_session::parse::ParseSess;
|
|||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::ops::Range;
|
||||
use std::{mem, slice};
|
||||
use std::{fmt, mem, slice};
|
||||
use thin_vec::ThinVec;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -146,7 +145,7 @@ pub struct Parser<'a> {
|
|||
/// The current token.
|
||||
pub token: Token,
|
||||
/// The spacing for the current token.
|
||||
pub token_spacing: Spacing,
|
||||
token_spacing: Spacing,
|
||||
/// The previous token.
|
||||
pub prev_token: Token,
|
||||
pub capture_cfg: bool,
|
||||
|
@ -187,7 +186,7 @@ pub struct Parser<'a> {
|
|||
current_closure: Option<ClosureSpans>,
|
||||
/// Whether the parser is allowed to do recovery.
|
||||
/// This is disabled when parsing macro arguments, see #103534
|
||||
pub recovery: Recovery,
|
||||
recovery: Recovery,
|
||||
}
|
||||
|
||||
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
|
||||
|
@ -197,10 +196,10 @@ rustc_data_structures::static_assert_size!(Parser<'_>, 264);
|
|||
|
||||
/// Stores span information about a closure.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClosureSpans {
|
||||
pub whole_closure: Span,
|
||||
pub closing_pipe: Span,
|
||||
pub body: Span,
|
||||
struct ClosureSpans {
|
||||
whole_closure: Span,
|
||||
closing_pipe: Span,
|
||||
body: Span,
|
||||
}
|
||||
|
||||
/// Indicates a range of tokens that should be replaced by
|
||||
|
@ -220,13 +219,13 @@ pub struct ClosureSpans {
|
|||
/// the first macro inner attribute to invoke a proc-macro).
|
||||
/// When create a `TokenStream`, the inner attributes get inserted
|
||||
/// into the proper place in the token stream.
|
||||
pub type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>);
|
||||
type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>);
|
||||
|
||||
/// Controls how we capture tokens. Capturing can be expensive,
|
||||
/// so we try to avoid performing capturing in cases where
|
||||
/// we will never need an `AttrTokenStream`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Capturing {
|
||||
enum Capturing {
|
||||
/// We aren't performing any capturing - this is the default mode.
|
||||
No,
|
||||
/// We are capturing tokens
|
||||
|
@ -374,13 +373,13 @@ pub enum FollowedByType {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Trailing {
|
||||
enum Trailing {
|
||||
No,
|
||||
Yes,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum TokenDescription {
|
||||
pub(super) enum TokenDescription {
|
||||
ReservedIdentifier,
|
||||
Keyword,
|
||||
ReservedKeyword,
|
||||
|
@ -388,7 +387,7 @@ pub enum TokenDescription {
|
|||
}
|
||||
|
||||
impl TokenDescription {
|
||||
pub fn from_token(token: &Token) -> Option<Self> {
|
||||
pub(super) fn from_token(token: &Token) -> Option<Self> {
|
||||
match token.kind {
|
||||
_ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier),
|
||||
_ if token.is_used_keyword() => Some(TokenDescription::Keyword),
|
||||
|
@ -502,7 +501,7 @@ impl<'a> Parser<'a> {
|
|||
/// Expect next token to be edible or inedible token. If edible,
|
||||
/// then consume it; if inedible, then return without consuming
|
||||
/// anything. Signal a fatal error if next token is unexpected.
|
||||
pub fn expect_one_of(
|
||||
fn expect_one_of(
|
||||
&mut self,
|
||||
edible: &[TokenKind],
|
||||
inedible: &[TokenKind],
|
||||
|
@ -572,7 +571,7 @@ impl<'a> Parser<'a> {
|
|||
/// the main purpose of this function is to reduce the cluttering of the suggestions list
|
||||
/// which using the normal eat method could introduce in some cases.
|
||||
#[inline]
|
||||
pub fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
|
||||
fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
|
||||
let is_present = self.check_noexpect(tok);
|
||||
if is_present {
|
||||
self.bump()
|
||||
|
@ -1520,7 +1519,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>(
|
||||
fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut Self) -> PResult<'a, R>,
|
||||
) -> PResult<'a, R> {
|
||||
|
@ -1541,8 +1540,10 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
// debug view of the parser's token stream, up to `{lookahead}` tokens
|
||||
pub fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
|
||||
// Debug view of the parser's token stream, up to `{lookahead}` tokens.
|
||||
// Only used when debugging.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
|
||||
struct DebugParser<'dbg> {
|
||||
parser: &'dbg Parser<'dbg>,
|
||||
lookahead: usize,
|
||||
|
@ -1618,7 +1619,7 @@ pub(crate) fn make_unclosed_delims_error(
|
|||
/// is then 'parsed' to build up an `AttrTokenStream` with nested
|
||||
/// `AttrTokenTree::Delimited` tokens.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FlatToken {
|
||||
enum FlatToken {
|
||||
/// A token - this holds both delimiter (e.g. '{' and '}')
|
||||
/// and non-delimiter tokens
|
||||
Token(Token),
|
||||
|
|
|
@ -21,14 +21,12 @@ impl MutVisitor for ToZzIdentMutVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
// Maybe add to `expand.rs`.
|
||||
macro_rules! assert_pred {
|
||||
($pred:expr, $predname:expr, $a:expr , $b:expr) => {{
|
||||
let pred_val = $pred;
|
||||
macro_rules! assert_matches_codepattern {
|
||||
($a:expr , $b:expr) => {{
|
||||
let a_val = $a;
|
||||
let b_val = $b;
|
||||
if !(pred_val(&a_val, &b_val)) {
|
||||
panic!("expected args satisfying {}, got {} and {}", $predname, a_val, b_val);
|
||||
if !matches_codepattern(&a_val, &b_val) {
|
||||
panic!("expected args satisfying `matches_codepattern`, got {} and {}", a_val, b_val);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -41,9 +39,7 @@ fn ident_transformation() {
|
|||
let mut krate =
|
||||
string_to_crate("#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string());
|
||||
zz_visitor.visit_crate(&mut krate);
|
||||
assert_pred!(
|
||||
matches_codepattern,
|
||||
"matches_codepattern",
|
||||
assert_matches_codepattern!(
|
||||
print_crate_items(&krate),
|
||||
"#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()
|
||||
);
|
||||
|
@ -61,9 +57,7 @@ fn ident_transformation_in_defs() {
|
|||
.to_string(),
|
||||
);
|
||||
zz_visitor.visit_crate(&mut krate);
|
||||
assert_pred!(
|
||||
matches_codepattern,
|
||||
"matches_codepattern",
|
||||
assert_matches_codepattern!(
|
||||
print_crate_items(&krate),
|
||||
"macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()
|
||||
);
|
||||
|
|
|
@ -20,7 +20,7 @@ use tracing::debug;
|
|||
|
||||
/// Specifies how to parse a path.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum PathStyle {
|
||||
pub(super) enum PathStyle {
|
||||
/// In some contexts, notably in expressions, paths with generic arguments are ambiguous
|
||||
/// with something else. For example, in expressions `segment < ....` can be interpreted
|
||||
/// as a comparison and `segment ( ....` can be interpreted as a function call.
|
||||
|
|
|
@ -31,7 +31,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parses a statement. This stops just before trailing semicolons on everything but items.
|
||||
/// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
|
||||
// Public for rustfmt usage.
|
||||
pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
|
||||
pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
|
||||
Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| {
|
||||
e.emit();
|
||||
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
|
||||
|
|
|
@ -127,7 +127,7 @@ impl<'a> Parser<'a> {
|
|||
/// Parse a type suitable for a field definition.
|
||||
/// The difference from `parse_ty` is that this version
|
||||
/// allows anonymous structs and unions.
|
||||
pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> {
|
||||
pub(super) fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> {
|
||||
if self.can_begin_anon_struct_or_union() {
|
||||
self.parse_anon_struct_or_union()
|
||||
} else {
|
||||
|
|
|
@ -25,15 +25,21 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
match attr_info {
|
||||
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
|
||||
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
|
||||
check_builtin_attribute(psess, attr, *name, *template)
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template),
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ if let AttrArgs::Eq(..) = attr.get_normal_item().args => {
|
||||
// All key-value attributes are restricted to meta-item syntax.
|
||||
parse_meta(psess, attr)
|
||||
.map_err(|err| {
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -42,6 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
|
|||
pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
|
||||
let item = attr.get_normal_item();
|
||||
Ok(MetaItem {
|
||||
unsafety: item.unsafety,
|
||||
span: attr.span,
|
||||
path: item.path.clone(),
|
||||
kind: match &item.args {
|
||||
|
@ -103,7 +110,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
|
|||
})
|
||||
}
|
||||
|
||||
pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
if let Delimiter::Parenthesis = delim {
|
||||
return;
|
||||
}
|
||||
|
@ -113,7 +120,7 @@ pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter
|
|||
});
|
||||
}
|
||||
|
||||
pub fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) {
|
||||
if let Delimiter::Parenthesis = delim {
|
||||
return;
|
||||
}
|
||||
|
@ -133,20 +140,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_attribute(
|
||||
psess: &ParseSess,
|
||||
attr: &Attribute,
|
||||
name: Symbol,
|
||||
template: AttributeTemplate,
|
||||
) {
|
||||
match parse_meta(psess, attr) {
|
||||
Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, name, template),
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_builtin_meta_item(
|
||||
psess: &ParseSess,
|
||||
meta: &MetaItem,
|
||||
|
|
|
@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level =
|
|||
passes_invalid_attr_at_crate_level_item =
|
||||
the inner attribute doesn't annotate this {$kind}
|
||||
|
||||
passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
|
||||
.suggestion = remove the `unsafe(...)`
|
||||
.note = extraneous unsafe is not allowed in attributes
|
||||
|
||||
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
|
||||
|
||||
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
|
||||
|
|
|
@ -10,7 +10,9 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem};
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::StashKey;
|
||||
use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan};
|
||||
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_feature::{
|
||||
is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP,
|
||||
};
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{self as hir};
|
||||
|
@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
let mut seen = FxHashMap::default();
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
self.check_unsafe_attr(attr);
|
||||
|
||||
match attr.path().as_slice() {
|
||||
[sym::diagnostic, sym::do_not_recommend] => {
|
||||
self.check_do_not_recommend(attr.span, hir_id, target)
|
||||
|
@ -308,6 +312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
true
|
||||
}
|
||||
|
||||
/// Checks if `unsafe()` is applied to an invalid attribute.
|
||||
fn check_unsafe_attr(&self, attr: &Attribute) {
|
||||
if !attr.is_doc_comment() {
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety {
|
||||
if !is_unsafe_attr(attr.name_or_empty()) {
|
||||
self.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
|
||||
fn check_diagnostic_on_unimplemented(
|
||||
&self,
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
|
|||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::middle::privacy::Level;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::lint::builtin::DEAD_CODE;
|
||||
|
@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
|
||||
struct Publicness {
|
||||
ty_is_public: bool,
|
||||
ty_and_all_fields_are_public: bool,
|
||||
}
|
||||
|
||||
impl Publicness {
|
||||
fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
|
||||
Self { ty_is_public, ty_and_all_fields_are_public }
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
|
||||
// treat PhantomData and positional ZST as public,
|
||||
// we don't want to lint types which only have them,
|
||||
// cause it's a common way to use such types to check things like well-formedness
|
||||
tcx.adt_def(id).all_fields().all(|field| {
|
||||
let field_type = tcx.type_of(field.did).instantiate_identity();
|
||||
if field_type.is_phantom_data() {
|
||||
return true;
|
||||
}
|
||||
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
|
||||
if is_positional
|
||||
&& tcx
|
||||
.layout_of(tcx.param_env(field.did).and(field_type))
|
||||
.map_or(true, |layout| layout.is_zst())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
field.vis.is_public()
|
||||
})
|
||||
}
|
||||
|
||||
/// check struct and its fields are public or not,
|
||||
/// for enum and union, just check they are public,
|
||||
/// and doesn't solve types like &T for now, just skip them
|
||||
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
|
||||
if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
|
||||
&& let Res::Def(def_kind, def_id) = path.res
|
||||
&& def_id.is_local()
|
||||
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
||||
{
|
||||
tcx.visibility(def_id).is_public()
|
||||
} else {
|
||||
true
|
||||
return match def_kind {
|
||||
DefKind::Enum | DefKind::Union => {
|
||||
let ty_is_public = tcx.visibility(def_id).is_public();
|
||||
Publicness::new(ty_is_public, ty_is_public)
|
||||
}
|
||||
DefKind::Struct => {
|
||||
let ty_is_public = tcx.visibility(def_id).is_public();
|
||||
Publicness::new(
|
||||
ty_is_public,
|
||||
ty_is_public && struct_all_fields_are_public(tcx, def_id),
|
||||
)
|
||||
}
|
||||
_ => Publicness::new(true, true),
|
||||
};
|
||||
}
|
||||
|
||||
Publicness::new(true, true)
|
||||
}
|
||||
|
||||
/// Determine if a work from the worklist is coming from the a `#[allow]`
|
||||
|
@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
{
|
||||
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
|
||||
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
|
||||
.ty_and_all_fields_are_public
|
||||
{
|
||||
// skip methods of private ty,
|
||||
// they would be solved in `solve_rest_impl_items`
|
||||
// skip impl-items of non pure pub ty,
|
||||
// cause we don't know the ty is constructed or not,
|
||||
// check these later in `solve_rest_impl_items`
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
|||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
||||
{
|
||||
if self.tcx.visibility(impl_item_id).is_public() {
|
||||
// for the public method, we don't know the trait item is used or not,
|
||||
// so we mark the method live if the self is used
|
||||
return self.live_symbols.contains(&local_def_id);
|
||||
}
|
||||
|
||||
if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
|
||||
&& let Some(local_id) = trait_item_id.as_local()
|
||||
{
|
||||
// for the private method, we can know the trait item is used or not,
|
||||
// for the local impl item, we can know the trait item is used or not,
|
||||
// so we mark the method live if the self is used and the trait item is used
|
||||
return self.live_symbols.contains(&local_id)
|
||||
&& self.live_symbols.contains(&local_def_id);
|
||||
self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
|
||||
} else {
|
||||
// for the foreign method and inherent pub method,
|
||||
// we don't know the trait item or the method is used or not,
|
||||
// so we mark the method live if the self is used
|
||||
self.live_symbols.contains(&local_def_id)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -747,7 +795,9 @@ fn check_item<'tcx>(
|
|||
.iter()
|
||||
.filter_map(|def_id| def_id.as_local());
|
||||
|
||||
let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
|
||||
let self_ty = tcx.hir().item(id).expect_impl().self_ty;
|
||||
let Publicness { ty_is_public, ty_and_all_fields_are_public } =
|
||||
ty_ref_to_pub_struct(tcx, self_ty);
|
||||
|
||||
// And we access the Map here to get HirId from LocalDefId
|
||||
for local_def_id in local_def_ids {
|
||||
|
@ -763,18 +813,20 @@ fn check_item<'tcx>(
|
|||
// for trait impl blocks,
|
||||
// mark the method live if the self_ty is public,
|
||||
// or the method is public and may construct self
|
||||
if of_trait
|
||||
&& (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
|
||||
|| tcx.visibility(local_def_id).is_public()
|
||||
&& (ty_is_pub || may_construct_self))
|
||||
if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy)
|
||||
|| tcx.visibility(local_def_id).is_public()
|
||||
&& (ty_and_all_fields_are_public || may_construct_self)
|
||||
{
|
||||
// if the impl item is public,
|
||||
// and the ty may be constructed or can be constructed in foreign crates,
|
||||
// mark the impl item live
|
||||
worklist.push((local_def_id, ComesFromAllowExpect::No));
|
||||
} else if let Some(comes_from_allow) =
|
||||
has_allow_dead_code_or_lang_attr(tcx, local_def_id)
|
||||
{
|
||||
worklist.push((local_def_id, comes_from_allow));
|
||||
} else if of_trait {
|
||||
// private method || public method not constructs self
|
||||
} else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
|
||||
// private impl items of traits || public impl items not constructs self
|
||||
unsolved_impl_items.push((id, local_def_id));
|
||||
}
|
||||
}
|
||||
|
@ -841,6 +893,14 @@ fn create_and_seed_worklist(
|
|||
effective_vis
|
||||
.is_public_at_level(Level::Reachable)
|
||||
.then_some(id)
|
||||
.filter(|&id|
|
||||
// checks impls, impl-items and pub structs with all public fields later
|
||||
match tcx.def_kind(id) {
|
||||
DefKind::Impl { .. } => false,
|
||||
DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
|
||||
DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()),
|
||||
_ => true
|
||||
})
|
||||
.map(|id| (id, ComesFromAllowExpect::No))
|
||||
})
|
||||
// Seed entry point
|
||||
|
@ -1113,10 +1173,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
|
|||
|| (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
|
||||
{
|
||||
for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
|
||||
// We have diagnosed unused methods in traits
|
||||
// We have diagnosed unused assoc consts and fns in traits
|
||||
if matches!(def_kind, DefKind::Impl { of_trait: true })
|
||||
&& tcx.def_kind(def_id) == DefKind::AssocFn
|
||||
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
|
||||
&& matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn)
|
||||
// skip unused public inherent methods,
|
||||
// cause we have diagnosed unconstructed struct
|
||||
|| matches!(def_kind, DefKind::Impl { of_trait: false })
|
||||
&& tcx.visibility(def_id).is_public()
|
||||
&& ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
|
||||
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_ast::Label;
|
||||
use rustc_ast::{ast, Label};
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
|
@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel {
|
|||
pub item: Option<ItemFollowingInnerAttr>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_invalid_attr_unsafe)]
|
||||
#[note]
|
||||
pub struct InvalidAttrUnsafe {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: ast::Path,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ItemFollowingInnerAttr {
|
||||
pub span: Span,
|
||||
|
|
|
@ -1962,6 +1962,7 @@ symbols! {
|
|||
unreachable_display,
|
||||
unreachable_macro,
|
||||
unrestricted_attribute_tokens,
|
||||
unsafe_attributes,
|
||||
unsafe_block_in_unsafe_fn,
|
||||
unsafe_cell,
|
||||
unsafe_cell_raw_get,
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#![feature(extract_if)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(option_take_if)]
|
||||
#![feature(never_type)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
|
|
@ -1216,7 +1216,6 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
|
|||
/// Basic usage:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(binary_heap_as_slice)]
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// use std::io::{self, Write};
|
||||
///
|
||||
|
@ -1225,7 +1224,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
|
|||
/// io::sink().write(heap.as_slice()).unwrap();
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[unstable(feature = "binary_heap_as_slice", issue = "83659")]
|
||||
#[stable(feature = "binary_heap_as_slice", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn as_slice(&self) -> &[T] {
|
||||
self.data.as_slice()
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#![feature(binary_heap_into_iter_sorted)]
|
||||
#![feature(binary_heap_drain_sorted)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(binary_heap_as_slice)]
|
||||
#![feature(inplace_iteration)]
|
||||
#![feature(iter_advance_by)]
|
||||
#![feature(iter_next_chunk)]
|
||||
|
|
|
@ -1708,8 +1708,6 @@ impl<T> Option<T> {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(option_take_if)]
|
||||
///
|
||||
/// let mut x = Some(42);
|
||||
///
|
||||
/// let prev = x.take_if(|v| if *v == 42 {
|
||||
|
@ -1726,7 +1724,7 @@ impl<T> Option<T> {
|
|||
/// assert_eq!(prev, Some(43));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "option_take_if", issue = "98934")]
|
||||
#[stable(feature = "option_take_if", since = "CURRENT_RUSTC_VERSION")]
|
||||
pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
|
||||
where
|
||||
P: FnOnce(&mut T) -> bool,
|
||||
|
|
|
@ -3,7 +3,7 @@ be edited manually.
|
|||
|
||||
To add bindings, edit `bindings.txt` then regenerate using the following command:
|
||||
|
||||
./x run generate-windows-sys && ./x fmt library/std
|
||||
./x run generate-windows-sys && ./x fmt
|
||||
|
||||
If you need to override generated functions or types then add them to
|
||||
`library/std/src/sys/pal/windows/c.rs`.
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::core::builder;
|
|||
use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
|
||||
use crate::core::config::TargetSelection;
|
||||
use crate::utils::channel::GitInfo;
|
||||
use crate::utils::exec::BootstrapCommand;
|
||||
use crate::utils::helpers::output;
|
||||
use crate::utils::helpers::{add_dylib_path, exe, t};
|
||||
use crate::Compiler;
|
||||
|
@ -110,9 +109,8 @@ impl Step for ToolBuild {
|
|||
&self.target,
|
||||
);
|
||||
|
||||
let mut cargo = Command::from(cargo);
|
||||
// we check this below
|
||||
let build_success = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure());
|
||||
let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {});
|
||||
|
||||
builder.save_toolstate(
|
||||
tool,
|
||||
|
|
|
@ -213,21 +213,39 @@ The valid emit kinds are:
|
|||
`CRATE_NAME.o`.
|
||||
|
||||
The output filename can be set with the [`-o` flag](#option-o-output). A
|
||||
suffix may be added to the filename with the [`-C extra-filename`
|
||||
flag](codegen-options/index.md#extra-filename). The files are written to the
|
||||
current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each
|
||||
emission type may also specify the output filename with the form `KIND=PATH`,
|
||||
which takes precedence over the `-o` flag.
|
||||
Specifying `-o -` or `--emit KIND=-` asks rustc to emit to stdout.
|
||||
Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to
|
||||
stdout despite it being a tty or not. This will result in an error if any
|
||||
binary output type is written to stdout that is a tty.
|
||||
This will also result in an error if multiple output types
|
||||
would be written to stdout, because they would be all mixed together.
|
||||
suffix may be added to the filename with the
|
||||
[`-C extra-filename` flag](codegen-options/index.md#extra-filename).
|
||||
|
||||
Output files are written to the current directory unless the
|
||||
[`--out-dir` flag](#option-out-dir) is used.
|
||||
|
||||
[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
|
||||
[LLVM IR]: https://llvm.org/docs/LangRef.html
|
||||
|
||||
### Custom paths for individual emit kinds
|
||||
|
||||
Each emit type can optionally be followed by `=` to specify an explicit output
|
||||
path that only applies to the output of that type. For example:
|
||||
|
||||
- `--emit=link,dep-info=/path/to/dep-info.d`
|
||||
- Emit the crate itself as normal,
|
||||
and also emit dependency info to the specified path.
|
||||
- `--emit=llvm-ir=-,mir`
|
||||
- Emit MIR to the default filename (based on crate name),
|
||||
and emit LLVM IR to stdout.
|
||||
|
||||
### Emitting to stdout
|
||||
|
||||
When using `--emit` or [`-o`](#option-o-output), output can be sent to stdout
|
||||
by specifying `-` as the path (e.g. `-o -`).
|
||||
|
||||
Binary output types can only be written to stdout if it is not a tty.
|
||||
Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to
|
||||
stdout regardless of whether it is a tty or not.
|
||||
|
||||
Only one type of output can be written to stdout. Attempting to write multiple
|
||||
types to stdout at the same time will result in an error.
|
||||
|
||||
<a id="option-print"></a>
|
||||
## `--print`: print compiler information
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::*;
|
||||
|
||||
use rustc_ast::{MetaItemLit, Path, StrStyle};
|
||||
use rustc_ast::{MetaItemLit, Path, Safety, StrStyle};
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::DUMMY_SP;
|
||||
|
@ -16,6 +16,7 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg {
|
|||
|
||||
fn dummy_meta_item_word(name: &str) -> MetaItem {
|
||||
MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(name)),
|
||||
kind: MetaItemKind::Word,
|
||||
span: DUMMY_SP,
|
||||
|
@ -25,6 +26,7 @@ fn dummy_meta_item_word(name: &str) -> MetaItem {
|
|||
fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
|
||||
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
|
||||
MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(name)),
|
||||
kind: MetaItemKind::NameValue(lit),
|
||||
span: DUMMY_SP,
|
||||
|
@ -34,6 +36,7 @@ fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> Meta
|
|||
macro_rules! dummy_meta_item_list {
|
||||
($name:ident, [$($list:ident),* $(,)?]) => {
|
||||
MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
kind: MetaItemKind::List(thin_vec![
|
||||
$(
|
||||
|
@ -48,6 +51,7 @@ macro_rules! dummy_meta_item_list {
|
|||
|
||||
($name:ident, [$($list:expr),* $(,)?]) => {
|
||||
MetaItem {
|
||||
unsafety: Safety::Default,
|
||||
path: Path::from_ident(Ident::from_str(stringify!($name))),
|
||||
kind: MetaItemKind::List(thin_vec![
|
||||
$(
|
||||
|
|
|
@ -3515,7 +3515,6 @@ impl<'test> TestCx<'test> {
|
|||
.arg(&self.testpaths.file.join("rmake.rs"))
|
||||
.env("TARGET", &self.config.target)
|
||||
.env("PYTHON", &self.config.python)
|
||||
.env("S", &src_root)
|
||||
.env("RUST_BUILD_STAGE", &self.config.stage_id)
|
||||
.env("RUSTC", cwd.join(&self.config.rustc_path))
|
||||
.env("TMPDIR", &rmake_out_dir)
|
||||
|
@ -3567,7 +3566,7 @@ impl<'test> TestCx<'test> {
|
|||
.env(dylib_env_var(), &dylib_env_paths)
|
||||
.env("TARGET", &self.config.target)
|
||||
.env("PYTHON", &self.config.python)
|
||||
.env("S", &src_root)
|
||||
.env("SOURCE_ROOT", &src_root)
|
||||
.env("RUST_BUILD_STAGE", &self.config.stage_id)
|
||||
.env("RUSTC", cwd.join(&self.config.rustc_path))
|
||||
.env("TMPDIR", &rmake_out_dir)
|
||||
|
|
|
@ -89,7 +89,7 @@ pub fn htmldocck() -> Command {
|
|||
|
||||
/// Path to the root rust-lang/rust source checkout.
|
||||
pub fn source_root() -> PathBuf {
|
||||
env_var("S").into()
|
||||
env_var("SOURCE_ROOT").into()
|
||||
}
|
||||
|
||||
/// Construct the static library name based on the platform.
|
||||
|
|
|
@ -214,22 +214,16 @@ impl Write for CombinedEncoder {
|
|||
}
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
|
||||
self.encoders
|
||||
.par_iter_mut()
|
||||
.map(|w| w.write_all(buf))
|
||||
.collect::<std::io::Result<Vec<()>>>()?;
|
||||
Ok(())
|
||||
self.encoders.par_iter_mut().try_for_each(|w| w.write_all(buf))
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
self.encoders.par_iter_mut().map(|w| w.flush()).collect::<std::io::Result<Vec<()>>>()?;
|
||||
Ok(())
|
||||
self.encoders.par_iter_mut().try_for_each(Write::flush)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder for CombinedEncoder {
|
||||
fn finish(self: Box<Self>) -> Result<(), Error> {
|
||||
self.encoders.into_par_iter().map(|e| e.finish()).collect::<Result<Vec<()>, Error>>()?;
|
||||
Ok(())
|
||||
self.encoders.into_par_iter().try_for_each(Encoder::finish)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,16 +22,16 @@ impl<T> Struct<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct LifeTimeOnly<'a> {
|
||||
pub struct _LifeTimeOnly<'a> {
|
||||
_a: &'a u32,
|
||||
}
|
||||
|
||||
impl<'a> LifeTimeOnly<'a> {
|
||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::foo
|
||||
impl<'a> _LifeTimeOnly<'a> {
|
||||
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo
|
||||
pub fn foo(&self) {}
|
||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::bar
|
||||
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar
|
||||
pub fn bar(&'a self) {}
|
||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::baz
|
||||
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz
|
||||
pub fn baz<'b>(&'b self) {}
|
||||
|
||||
pub fn non_instantiated<T>(&self) {}
|
||||
|
|
|
@ -5,44 +5,44 @@
|
|||
|
||||
use std::ops::{Add, Deref, Index, IndexMut};
|
||||
|
||||
pub struct Indexable {
|
||||
pub struct _Indexable {
|
||||
data: [u8; 3],
|
||||
}
|
||||
|
||||
impl Index<usize> for Indexable {
|
||||
impl Index<usize> for _Indexable {
|
||||
type Output = u8;
|
||||
|
||||
//~ MONO_ITEM fn <Indexable as std::ops::Index<usize>>::index
|
||||
//~ MONO_ITEM fn <_Indexable as std::ops::Index<usize>>::index
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
if index >= 3 { &self.data[0] } else { &self.data[index] }
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Indexable {
|
||||
//~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut
|
||||
impl IndexMut<usize> for _Indexable {
|
||||
//~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
if index >= 3 { &mut self.data[0] } else { &mut self.data[index] }
|
||||
}
|
||||
}
|
||||
|
||||
//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::eq
|
||||
//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne
|
||||
//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq
|
||||
//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne
|
||||
#[derive(PartialEq)]
|
||||
pub struct Equatable(u32);
|
||||
pub struct _Equatable(u32);
|
||||
|
||||
impl Add<u32> for Equatable {
|
||||
impl Add<u32> for _Equatable {
|
||||
type Output = u32;
|
||||
|
||||
//~ MONO_ITEM fn <Equatable as std::ops::Add<u32>>::add
|
||||
//~ MONO_ITEM fn <_Equatable as std::ops::Add<u32>>::add
|
||||
fn add(self, rhs: u32) -> u32 {
|
||||
self.0 + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Equatable {
|
||||
impl Deref for _Equatable {
|
||||
type Target = u32;
|
||||
|
||||
//~ MONO_ITEM fn <Equatable as std::ops::Deref>::deref
|
||||
//~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use run_make_support::{aux_build, rustc};
|
||||
use run_make_support::{aux_build, rustc, source_root};
|
||||
|
||||
fn main() {
|
||||
aux_build().input("stable.rs").emit("metadata").run();
|
||||
|
@ -17,7 +17,7 @@ fn main() {
|
|||
rustc().input("main.rs").emit("metadata").extern_("stable", &stable_path).command_output();
|
||||
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let version = include_str!(concat!(env!("S"), "/src/version"));
|
||||
let version = std::fs::read_to_string(source_root().join("src/version")).unwrap();
|
||||
let expected_string = format!("stable since {}", version.trim());
|
||||
assert!(stderr.contains(&expected_string));
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ fn test_stable_mir() -> ControlFlow<()> {
|
|||
// Get all items and split generic vs monomorphic items.
|
||||
let (generic, mono): (Vec<_>, Vec<_>) =
|
||||
items.into_iter().partition(|item| item.requires_monomorphization());
|
||||
assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant");
|
||||
assert_eq!(mono.len(), 4, "Expected 2 mono functions and one constant");
|
||||
assert_eq!(generic.len(), 2, "Expected 2 generic functions");
|
||||
|
||||
// For all monomorphic items, get the correspondent instances.
|
||||
|
@ -57,8 +57,9 @@ fn test_body(body: mir::Body) {
|
|||
for term in body.blocks.iter().map(|bb| &bb.terminator) {
|
||||
match &term.kind {
|
||||
Call { func, .. } => {
|
||||
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable!
|
||||
() };
|
||||
let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else {
|
||||
unreachable!()
|
||||
};
|
||||
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
|
||||
let instance = Instance::resolve(def, &args).unwrap();
|
||||
let mangled_name = instance.mangled_name();
|
||||
|
@ -102,6 +103,9 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
|||
write!(
|
||||
file,
|
||||
r#"
|
||||
|
||||
struct Foo(());
|
||||
|
||||
pub fn ty_param<T>(t: &T) -> T where T: Clone {{
|
||||
t.clone()
|
||||
}}
|
||||
|
@ -116,6 +120,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
|||
}}
|
||||
|
||||
pub fn monomorphic() {{
|
||||
Foo(());
|
||||
let v = vec![10];
|
||||
let dup = ty_param(&v);
|
||||
assert_eq!(v, dup);
|
||||
|
|
7
tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
Normal file
7
tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
//@ build-pass
|
||||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[cfg_attr(all(), unsafe(no_mangle))]
|
||||
fn a() {}
|
||||
|
||||
fn main() {}
|
6
tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
Normal file
6
tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)`
|
||||
struct Foo;
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,8 @@
|
|||
error: traits in `#[derive(...)]` don't accept `unsafe(...)`
|
||||
--> $DIR/derive-unsafe-attributes.rs:3:10
|
||||
|
|
||||
LL | #[derive(unsafe(Debug))]
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
9
tests/ui/attributes/unsafe/double-unsafe-attributes.rs
Normal file
9
tests/ui/attributes/unsafe/double-unsafe-attributes.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[unsafe(unsafe(no_mangle))]
|
||||
//~^ ERROR expected identifier, found keyword `unsafe`
|
||||
//~| ERROR cannot find attribute `r#unsafe` in this scope
|
||||
//~| ERROR `r#unsafe` is not an unsafe attribute
|
||||
fn a() {}
|
||||
|
||||
fn main() {}
|
27
tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
Normal file
27
tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error: expected identifier, found keyword `unsafe`
|
||||
--> $DIR/double-unsafe-attributes.rs:3:10
|
||||
|
|
||||
LL | #[unsafe(unsafe(no_mangle))]
|
||||
| ^^^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: escape `unsafe` to use it as an identifier
|
||||
|
|
||||
LL | #[unsafe(r#unsafe(no_mangle))]
|
||||
| ++
|
||||
|
||||
error: cannot find attribute `r#unsafe` in this scope
|
||||
--> $DIR/double-unsafe-attributes.rs:3:10
|
||||
|
|
||||
LL | #[unsafe(unsafe(no_mangle))]
|
||||
| ^^^^^^
|
||||
|
||||
error: `r#unsafe` is not an unsafe attribute
|
||||
--> $DIR/double-unsafe-attributes.rs:3:3
|
||||
|
|
||||
LL | #[unsafe(unsafe(no_mangle))]
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: extraneous unsafe is not allowed in attributes
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
7
tests/ui/attributes/unsafe/unsafe-attributes.rs
Normal file
7
tests/ui/attributes/unsafe/unsafe-attributes.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
//@ build-pass
|
||||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn a() {}
|
||||
|
||||
fn main() {}
|
6
tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
Normal file
6
tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
|
||||
struct Foo {}
|
||||
|
||||
fn main() {}
|
10
tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
Normal file
10
tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
error: `repr` is not an unsafe attribute
|
||||
--> $DIR/unsafe-safe-attribute.rs:3:3
|
||||
|
|
||||
LL | #[unsafe(repr(C))]
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: extraneous unsafe is not allowed in attributes
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#![feature(unsafe_attributes)]
|
||||
|
||||
#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
|
||||
message = "testing",
|
||||
))]
|
||||
trait Foo {}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,10 @@
|
|||
error: `diagnostic::on_unimplemented` is not an unsafe attribute
|
||||
--> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3
|
||||
|
|
||||
LL | #[unsafe(diagnostic::on_unimplemented(
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: extraneous unsafe is not allowed in attributes
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
extern crate re_rebalance_coherence_lib as lib;
|
||||
use lib::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Oracle;
|
||||
impl Backend for Oracle {}
|
||||
impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
//@ run-pass
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(C)]
|
||||
pub struct Loaf<T: Sized, const N: usize = 1> {
|
||||
head: [T; N],
|
||||
|
|
|
@ -16,7 +16,8 @@ impl BlockCipher for BarCipher {
|
|||
const BLOCK_SIZE: usize = 32;
|
||||
}
|
||||
|
||||
pub struct Block<C>(#[allow(dead_code)] C);
|
||||
#[allow(dead_code)]
|
||||
pub struct Block<C>(C);
|
||||
|
||||
pub fn test<C: BlockCipher, const M: usize>()
|
||||
where
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(transparent)]
|
||||
pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#![forbid(dead_code)]
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Whatever {
|
||||
pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
|
||||
pub field0: (),
|
||||
field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
|
||||
field1: (),
|
||||
field2: (),
|
||||
field3: (),
|
||||
field4: (),
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
error: fields `field1`, `field2`, `field3`, and `field4` are never read
|
||||
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
|
||||
error: struct `Whatever` is never constructed
|
||||
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
|
||||
|
|
||||
LL | pub struct Whatever {
|
||||
| -------- fields in this struct
|
||||
LL | pub field0: (),
|
||||
LL | field1: (),
|
||||
| ^^^^^^
|
||||
LL | field2: (),
|
||||
| ^^^^^^
|
||||
LL | field3: (),
|
||||
| ^^^^^^
|
||||
LL | field4: (),
|
||||
| ^^^^^^
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
|
||||
note: the lint level is defined here
|
||||
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
|
||||
|
|
||||
|
|
8
tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
Normal file
8
tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#[unsafe(no_mangle)] //~ ERROR [E0658]
|
||||
extern "C" fn foo() {
|
||||
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo();
|
||||
}
|
13
tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
Normal file
13
tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
Normal file
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: `#[unsafe()]` markers for attributes are experimental
|
||||
--> $DIR/feature-gate-unsafe-attributes.rs:1:3
|
||||
|
|
||||
LL | #[unsafe(no_mangle)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #123757 <https://github.com/rust-lang/rust/issues/123757> for more information
|
||||
= help: add `#![feature(unsafe_attributes)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
|
@ -44,6 +44,7 @@ pub trait MyTrait<T> {
|
|||
fn dummy(&self, t: T) -> T { panic!() }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct MyContainer<'a, T:'a> {
|
||||
foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
|
||||
}
|
||||
|
|
|
@ -46,11 +46,10 @@ struct SemiUsedStruct;
|
|||
impl SemiUsedStruct {
|
||||
fn la_la_la() {}
|
||||
}
|
||||
struct StructUsedAsField;
|
||||
struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed
|
||||
pub struct StructUsedInEnum;
|
||||
struct StructUsedInGeneric;
|
||||
pub struct PubStruct2 {
|
||||
#[allow(dead_code)]
|
||||
pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed
|
||||
struct_used_as_field: *const StructUsedAsField
|
||||
}
|
||||
|
||||
|
|
|
@ -22,14 +22,26 @@ error: struct `PrivStruct` is never constructed
|
|||
LL | struct PrivStruct;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: struct `StructUsedAsField` is never constructed
|
||||
--> $DIR/lint-dead-code-1.rs:49:8
|
||||
|
|
||||
LL | struct StructUsedAsField;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: struct `PubStruct2` is never constructed
|
||||
--> $DIR/lint-dead-code-1.rs:52:12
|
||||
|
|
||||
LL | pub struct PubStruct2 {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: enum `priv_enum` is never used
|
||||
--> $DIR/lint-dead-code-1.rs:64:6
|
||||
--> $DIR/lint-dead-code-1.rs:63:6
|
||||
|
|
||||
LL | enum priv_enum { foo2, bar2 }
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: variant `bar3` is never constructed
|
||||
--> $DIR/lint-dead-code-1.rs:67:5
|
||||
--> $DIR/lint-dead-code-1.rs:66:5
|
||||
|
|
||||
LL | enum used_enum {
|
||||
| --------- variant in this enum
|
||||
|
@ -38,25 +50,25 @@ LL | bar3
|
|||
| ^^^^
|
||||
|
||||
error: function `priv_fn` is never used
|
||||
--> $DIR/lint-dead-code-1.rs:88:4
|
||||
--> $DIR/lint-dead-code-1.rs:87:4
|
||||
|
|
||||
LL | fn priv_fn() {
|
||||
| ^^^^^^^
|
||||
|
||||
error: function `foo` is never used
|
||||
--> $DIR/lint-dead-code-1.rs:93:4
|
||||
--> $DIR/lint-dead-code-1.rs:92:4
|
||||
|
|
||||
LL | fn foo() {
|
||||
| ^^^
|
||||
|
||||
error: function `bar` is never used
|
||||
--> $DIR/lint-dead-code-1.rs:98:4
|
||||
--> $DIR/lint-dead-code-1.rs:97:4
|
||||
|
|
||||
LL | fn bar() {
|
||||
| ^^^
|
||||
|
||||
error: function `baz` is never used
|
||||
--> $DIR/lint-dead-code-1.rs:102:4
|
||||
--> $DIR/lint-dead-code-1.rs:101:4
|
||||
|
|
||||
LL | fn baz() -> impl Copy {
|
||||
| ^^^
|
||||
|
@ -67,5 +79,5 @@ error: struct `Bar` is never constructed
|
|||
LL | pub struct Bar;
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
|
20
tests/ui/lint/dead-code/unused-assoc-const.rs
Normal file
20
tests/ui/lint/dead-code/unused-assoc-const.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
#![deny(dead_code)]
|
||||
|
||||
trait Trait {
|
||||
const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used
|
||||
const USED_CONST: i32;
|
||||
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
pub struct T(());
|
||||
|
||||
impl Trait for T {
|
||||
const UNUSED_CONST: i32 = 0;
|
||||
const USED_CONST: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
T(()).foo();
|
||||
T::USED_CONST;
|
||||
}
|
16
tests/ui/lint/dead-code/unused-assoc-const.stderr
Normal file
16
tests/ui/lint/dead-code/unused-assoc-const.stderr
Normal file
|
@ -0,0 +1,16 @@
|
|||
error: associated constant `UNUSED_CONST` is never used
|
||||
--> $DIR/unused-assoc-const.rs:4:11
|
||||
|
|
||||
LL | trait Trait {
|
||||
| ----- associated constant in this trait
|
||||
LL | const UNUSED_CONST: i32;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused-assoc-const.rs:1:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
48
tests/ui/lint/dead-code/unused-pub-struct.rs
Normal file
48
tests/ui/lint/dead-code/unused-pub-struct.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#![deny(dead_code)]
|
||||
|
||||
pub struct NotLint1(());
|
||||
pub struct NotLint2(std::marker::PhantomData<i32>);
|
||||
|
||||
pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed
|
||||
|
||||
impl NeverConstructed {
|
||||
pub fn not_construct_self(&self) {}
|
||||
}
|
||||
|
||||
impl Clone for NeverConstructed {
|
||||
fn clone(&self) -> NeverConstructed {
|
||||
NeverConstructed(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Trait {
|
||||
fn not_construct_self(&self);
|
||||
}
|
||||
|
||||
impl Trait for NeverConstructed {
|
||||
fn not_construct_self(&self) {
|
||||
self.0;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Constructed(i32);
|
||||
|
||||
impl Constructed {
|
||||
pub fn construct_self() -> Self {
|
||||
Constructed(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Constructed {
|
||||
fn clone(&self) -> Constructed {
|
||||
Constructed(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait for Constructed {
|
||||
fn not_construct_self(&self) {
|
||||
self.0;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
14
tests/ui/lint/dead-code/unused-pub-struct.stderr
Normal file
14
tests/ui/lint/dead-code/unused-pub-struct.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: struct `NeverConstructed` is never constructed
|
||||
--> $DIR/unused-pub-struct.rs:6:12
|
||||
|
|
||||
LL | pub struct NeverConstructed(i32);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/unused-pub-struct.rs:1:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
// Regression test for issues #100790 and #106439.
|
||||
//@ run-rustfix
|
||||
|
||||
pub struct Example(#[allow(dead_code)] usize)
|
||||
#[allow(dead_code)]
|
||||
pub struct Example(usize)
|
||||
where
|
||||
(): Sized;
|
||||
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// Regression test for issues #100790 and #106439.
|
||||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Example
|
||||
where
|
||||
(): Sized,
|
||||
(#[allow(dead_code)] usize);
|
||||
(usize);
|
||||
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
||||
|
||||
struct _Demo
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
error: where clauses are not allowed before tuple struct bodies
|
||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1
|
||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1
|
||||
|
|
||||
LL | pub struct Example
|
||||
| ------- while parsing this tuple struct
|
||||
LL | / where
|
||||
LL | | (): Sized,
|
||||
| |______________^ unexpected where clause
|
||||
LL | (#[allow(dead_code)] usize);
|
||||
| --------------------------- the struct body
|
||||
LL | (usize);
|
||||
| ------- the struct body
|
||||
|
|
||||
help: move the body before the where clause
|
||||
|
|
||||
LL ~ pub struct Example(#[allow(dead_code)] usize)
|
||||
LL ~ pub struct Example(usize)
|
||||
LL | where
|
||||
LL ~ (): Sized;
|
||||
|
|
||||
|
||||
error: where clauses are not allowed before tuple struct bodies
|
||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1
|
||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1
|
||||
|
|
||||
LL | struct _Demo
|
||||
| ----- while parsing this tuple struct
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//@ run-rustfix
|
||||
|
||||
pub struct T(#[allow(dead_code)] String);
|
||||
#[allow(dead_code)]
|
||||
pub struct T(String);
|
||||
//~^ ERROR missing `struct` for struct definition
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//@ run-rustfix
|
||||
|
||||
pub T(#[allow(dead_code)] String);
|
||||
#[allow(dead_code)]
|
||||
pub T(String);
|
||||
//~^ ERROR missing `struct` for struct definition
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
error: missing `struct` for struct definition
|
||||
--> $DIR/pub-ident-struct-4.rs:3:4
|
||||
--> $DIR/pub-ident-struct-4.rs:4:4
|
||||
|
|
||||
LL | pub T(#[allow(dead_code)] String);
|
||||
LL | pub T(String);
|
||||
| ^
|
||||
|
|
||||
help: add `struct` here to parse `T` as a public struct
|
||||
|
|
||||
LL | pub struct T(#[allow(dead_code)] String);
|
||||
LL | pub struct T(String);
|
||||
| ++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct P<'a> {
|
||||
_ptr: *const &'a u8,
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
#![allow(unused_variables)]
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Fd(u32);
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn foo(a: u32) {}
|
||||
|
||||
impl Drop for Fd {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//@ run-pass
|
||||
pub struct Z(#[allow(dead_code)] &'static Z);
|
||||
#[allow(dead_code)]
|
||||
pub struct Z(&'static Z);
|
||||
|
||||
pub fn main() {}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//@ run-rustfix
|
||||
// https://github.com/rust-lang/rust/issues/79076
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
||||
pub struct Struct<T: std::clone::Clone>(T);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//@ run-rustfix
|
||||
// https://github.com/rust-lang/rust/issues/79076
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
||||
pub struct Struct<T>(T);
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
error[E0277]: the trait bound `T: Clone` is not satisfied
|
||||
--> $DIR/derive-clone-for-eq.rs:4:17
|
||||
--> $DIR/derive-clone-for-eq.rs:5:17
|
||||
|
|
||||
LL | #[derive(Clone, Eq)]
|
||||
| ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
|
||||
|
|
||||
note: required for `Struct<T>` to implement `PartialEq`
|
||||
--> $DIR/derive-clone-for-eq.rs:7:19
|
||||
--> $DIR/derive-clone-for-eq.rs:8:19
|
||||
|
|
||||
LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
|
||||
| ----- ^^^^^^^^^^^^ ^^^^^^^^^
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#[allow(dead_code)]
|
||||
pub struct LipogramCorpora {
|
||||
selections: Vec<(char, Option<String>)>,
|
||||
}
|
||||
|
@ -17,6 +18,7 @@ impl LipogramCorpora {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct LipogramCorpora2 {
|
||||
selections: Vec<(char, Result<String, String>)>,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#[allow(dead_code)]
|
||||
pub struct LipogramCorpora {
|
||||
selections: Vec<(char, Option<String>)>,
|
||||
}
|
||||
|
@ -17,6 +18,7 @@ impl LipogramCorpora {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct LipogramCorpora2 {
|
||||
selections: Vec<(char, Result<String, String>)>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
|
||||
--> $DIR/option-content-move.rs:10:20
|
||||
--> $DIR/option-content-move.rs:11:20
|
||||
|
|
||||
LL | if selection.1.unwrap().contains(selection.0) {
|
||||
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
||||
|
@ -19,7 +19,7 @@ LL | if selection.1.clone().unwrap().contains(selection.0) {
|
|||
| ++++++++
|
||||
|
||||
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
|
||||
--> $DIR/option-content-move.rs:28:20
|
||||
--> $DIR/option-content-move.rs:30:20
|
||||
|
|
||||
LL | if selection.1.unwrap().contains(selection.0) {
|
||||
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
||||
|
|
|
@ -7,6 +7,7 @@ pub trait Trait2<A> {
|
|||
fn doit(&self) -> A;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct Impl<A1, A2, A3> {
|
||||
m1: marker::PhantomData<(A1,A2,A3)>,
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue