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:
bors
2024-06-07 20:12:49 +00:00
89 changed files with 745 additions and 234 deletions
+8 -1
View File
@@ -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 @@ pub fn from_ident(ident: Ident) -> Self {
#[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]`.
+27 -8
View File
@@ -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 @@ fn value_str(&self) -> Option<Symbol> {
}
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 @@ fn from_tokens<'a, I>(tokens: &mut iter::Peekable<I>) -> Option<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> {
+6 -4
View File
@@ -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);
+1
View File
@@ -1805,6 +1805,7 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'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),
+1
View File
@@ -905,6 +905,7 @@ fn lower_attr(&self, attr: &Attribute) -> Attribute {
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 @@ macro_rules! gate_all {
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::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),
+12 -1
View File
@@ -2,7 +2,7 @@
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 @@ fn expand(
// 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,
+17 -3
View File
@@ -666,7 +666,7 @@ pub fn item_const(
// 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 @@ pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
// 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,
)
}
}
+8 -1
View File
@@ -778,7 +778,14 @@ fn expand_invoc(
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) => {
+58 -5
View File
@@ -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 struct 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 struct 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 struct 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();
+2 -2
View File
@@ -123,8 +123,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
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};
+2
View File
@@ -620,6 +620,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(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.
+1 -1
View File
@@ -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
+32 -3
View File
@@ -7,7 +7,7 @@
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 @@ pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::Attr
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 @@ pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
}
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> {
+15 -11
View File
@@ -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 @@ fn check_too_many_raw_str_terminators(&mut self, err: &mut Diag<'_>) -> bool {
}
}
pub fn maybe_suggest_struct_literal(
pub(super) fn maybe_suggest_struct_literal(
&mut self,
lo: Span,
s: BlockCheckMode,
@@ -2459,7 +2459,7 @@ pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<
/// 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 @@ pub fn handle_ambiguous_unbraced_const_arg(
/// - 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 @@ fn recover_const_param_decl(&mut self, ty_generics: Option<&Generics>) -> Option
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 @@ pub fn recover_const_param_declaration(
/// 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 @@ pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
}
/// 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 @@ pub(crate) fn maybe_err_dotdotlt_syntax(&self, maybe_lt: Token, mut err: PErr<'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 @@ fn conflict_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) ->
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(());
+6 -2
View File
@@ -431,7 +431,7 @@ fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
/// 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 @@ fn parse_expr_dot_or_call_with_(&mut self, mut e: P<Expr>, lo: Span) -> PResult<
}
}
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 {
+2 -2
View File
@@ -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.
+22 -21
View File
@@ -11,14 +11,13 @@
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_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 @@ pub struct Parser<'a> {
/// 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 @@ pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
/// 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 @@ fn check_noexpect(&self, tok: &TokenKind) -> bool {
/// 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 @@ fn parse_abi(&mut self) -> Option<StrLit> {
}
}
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 @@ fn is_import_coupler(&mut self) -> bool {
})
}
// 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 @@ fn visit_ident(&mut self, ident: &mut Ident) {
}
}
// 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()
);
+1 -1
View File
@@ -20,7 +20,7 @@
/// 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.
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -127,7 +127,7 @@ pub(super) fn parse_ty_with_generics_recovery(
/// 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 {
+14 -21
View File
@@ -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,
+4
View File
@@ -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
+20 -1
View File
@@ -10,7 +10,9 @@
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 @@ fn check_attributes(
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 @@ fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target)
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,
+93 -28
View File
@@ -15,7 +15,7 @@
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 @@ fn visit_node(&mut self, node: Node<'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 @@ fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: Local
&& 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;
}
+10 -1
View File
@@ -4,7 +4,7 @@
};
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,
+1
View File
@@ -1962,6 +1962,7 @@
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 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
/// Basic usage:
///
/// ```
/// #![feature(binary_heap_as_slice)]
/// use std::collections::BinaryHeap;
/// use std::io::{self, Write};
///
@@ -1225,7 +1224,7 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
/// 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()
}
-1
View File
@@ -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)]
+1 -3
View File
@@ -1708,8 +1708,6 @@ pub const fn take(&mut self) -> 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 @@ pub const fn take(&mut self) -> 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,
+1 -1
View File
@@ -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`.
+1 -3
View File
@@ -9,7 +9,6 @@
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 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
&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,
+29 -11
View File
@@ -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
+5 -1
View File
@@ -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![
$(
+1 -2
View File
@@ -3515,7 +3515,6 @@ fn run_rmake_v2_test(&self) {
.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 @@ fn run_rmake_v2_test(&self) {
.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)
+1 -1
View File
@@ -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.
+3 -9
View File
@@ -214,22 +214,16 @@ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
}
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 @@ fn get<T2>(self, x: T2) -> (T, T2) {
}
}
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 @@ pub fn ty_param<T>(t: &T) -> T where T: Clone {{
}}
pub fn monomorphic() {{
Foo(());
let v = vec![10];
let dup = ty_param(&v);
assert_eq!(v, dup);
@@ -0,0 +1,7 @@
//@ build-pass
#![feature(unsafe_attributes)]
#[cfg_attr(all(), unsafe(no_mangle))]
fn a() {}
fn main() {}
@@ -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
@@ -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() {}
@@ -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
@@ -0,0 +1,7 @@
//@ build-pass
#![feature(unsafe_attributes)]
#[unsafe(no_mangle)]
fn a() {}
fn main() {}
@@ -0,0 +1,6 @@
#![feature(unsafe_attributes)]
#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
struct Foo {}
fn main() {}
@@ -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
|
@@ -0,0 +1,8 @@
#[unsafe(no_mangle)] //~ ERROR [E0658]
extern "C" fn foo() {
}
fn main() {
foo();
}
@@ -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`.
+1
View File
@@ -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)> ,
}
+2 -3
View File
@@ -46,11 +46,10 @@ struct UsedStruct1 {
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
@@ -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;
}
@@ -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
@@ -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() {}
@@ -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
+2 -1
View File
@@ -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() {}
+2 -1
View File
@@ -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() {}
+3 -3
View File
@@ -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
+1
View File
@@ -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 @@ pub fn validate_all(&mut self) -> Result<(), char> {
}
}
#[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
+1
View File
@@ -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)>,
/*