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
commit 804421dff5
89 changed files with 745 additions and 234 deletions

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 @@ 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]`.

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 @@ 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> {

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);

View file

@ -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),

View file

@ -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,

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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

View file

@ -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),

View file

@ -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!(),
}
}

View file

@ -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]

View file

@ -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,

View file

@ -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,
)
}
}

View file

@ -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) => {

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 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();

View file

@ -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};

View file

@ -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.

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

View file

@ -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> {

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 @@ 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(());

View file

@ -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 {

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.

View file

@ -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),

View file

@ -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()
);

View file

@ -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.

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);

View file

@ -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 {

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,

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

View file

@ -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,

View file

@ -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;
}

View file

@ -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,

View file

@ -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,

View file

@ -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

View file

@ -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()
}

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)]

View file

@ -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,

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`.

View file

@ -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,

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

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![
$(

View file

@ -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)

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.

View file

@ -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)
}
}

View file

@ -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) {}

View file

@ -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
}

View file

@ -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));
}

View file

@ -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);

View file

@ -0,0 +1,7 @@
//@ build-pass
#![feature(unsafe_attributes)]
#[cfg_attr(all(), unsafe(no_mangle))]
fn a() {}
fn main() {}

View file

@ -0,0 +1,6 @@
#![feature(unsafe_attributes)]
#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)`
struct Foo;
fn main() {}

View file

@ -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

View 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() {}

View 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

View file

@ -0,0 +1,7 @@
//@ build-pass
#![feature(unsafe_attributes)]
#[unsafe(no_mangle)]
fn a() {}
fn main() {}

View file

@ -0,0 +1,6 @@
#![feature(unsafe_attributes)]
#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
struct Foo {}
fn main() {}

View 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

View file

@ -0,0 +1,8 @@
#![feature(unsafe_attributes)]
#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
message = "testing",
))]
trait Foo {}
fn main() {}

View file

@ -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

View file

@ -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> {}

View file

@ -2,6 +2,7 @@
//@ run-pass
#[allow(dead_code)]
#[repr(C)]
pub struct Loaf<T: Sized, const N: usize = 1> {
head: [T; N],

View file

@ -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

View file

@ -6,6 +6,7 @@
use std::mem::MaybeUninit;
#[allow(dead_code)]
#[repr(transparent)]
pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);

View file

@ -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: (),

View file

@ -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
|

View file

@ -0,0 +1,8 @@
#[unsafe(no_mangle)] //~ ERROR [E0658]
extern "C" fn foo() {
}
fn main() {
foo();
}

View 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`.

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)> ,
}

View file

@ -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
}

View file

@ -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

View 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;
}

View 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

View 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() {}

View 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

View file

@ -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

View file

@ -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

View file

@ -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

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() {}

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() {}

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

View file

@ -5,6 +5,7 @@
//@ pretty-expanded FIXME #23616
#[allow(dead_code)]
pub struct P<'a> {
_ptr: *const &'a u8,
}

View file

@ -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 {

View file

@ -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() {}

View file

@ -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);

View file

@ -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);

View file

@ -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>
| ----- ^^^^^^^^^^^^ ^^^^^^^^^

View file

@ -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>)>,
}

View file

@ -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>)>,
}

View file

@ -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

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)>,
/*