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"]`. /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct MetaItem { pub struct MetaItem {
pub unsafety: Safety,
pub path: Path, pub path: Path,
pub kind: MetaItemKind, pub kind: MetaItemKind,
pub span: Span, pub span: Span,
@ -2823,7 +2824,12 @@ pub struct NormalAttr {
impl NormalAttr { impl NormalAttr {
pub fn from_ident(ident: Ident) -> Self { pub fn from_ident(ident: Ident) -> Self {
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, tokens: None,
} }
} }
@ -2831,6 +2837,7 @@ impl NormalAttr {
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct AttrItem { pub struct AttrItem {
pub unsafety: Safety,
pub path: Path, pub path: Path,
pub args: AttrArgs, pub args: AttrArgs,
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. // 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. //! 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::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit};
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr};
use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; use crate::ast::{Path, PathSegment, DUMMY_NODE_ID};
@ -238,7 +240,12 @@ impl AttrItem {
} }
pub fn meta(&self, span: Span) -> Option<MetaItem> { 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> { pub fn meta_kind(&self) -> Option<MetaItemKind> {
@ -371,7 +378,10 @@ impl MetaItem {
_ => path.span.hi(), _ => path.span.hi(),
}; };
let span = path.span.with_hi(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( pub fn mk_attr(
g: &AttrIdGenerator, g: &AttrIdGenerator,
style: AttrStyle, style: AttrStyle,
unsafety: Safety,
path: Path, path: Path,
args: AttrArgs, args: AttrArgs,
span: Span, span: Span,
) -> Attribute { ) -> 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( 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 path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Empty; 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( pub fn mk_attr_nested_word(
g: &AttrIdGenerator, g: &AttrIdGenerator,
style: AttrStyle, style: AttrStyle,
unsafety: Safety,
outer: Symbol, outer: Symbol,
inner: Symbol, inner: Symbol,
span: Span, span: Span,
@ -601,12 +619,13 @@ pub fn mk_attr_nested_word(
delim: Delimiter::Parenthesis, delim: Delimiter::Parenthesis,
tokens: inner_tokens, 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( pub fn mk_attr_name_value_str(
g: &AttrIdGenerator, g: &AttrIdGenerator,
style: AttrStyle, style: AttrStyle,
unsafety: Safety,
name: Symbol, name: Symbol,
val: Symbol, val: Symbol,
span: Span, span: Span,
@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str(
}); });
let path = Path::from_ident(Ident::new(name, span)); let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); 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> { 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; let Attribute { kind, id: _, style: _, span } = attr;
match kind { match kind {
AttrKind::Normal(normal) => { AttrKind::Normal(normal) => {
let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = let NormalAttr {
&mut **normal; item: AttrItem { unsafety: _, path, args, tokens },
tokens: attr_tokens,
} = &mut **normal;
vis.visit_path(path); vis.visit_path(path);
visit_attr_args(args, vis); visit_attr_args(args, vis);
visit_lazy_tts(tokens, 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) { 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 { match kind {
MetaItemKind::Word => {} MetaItemKind::Word => {}
MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), 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::NtTy(ty) => vis.visit_ty(ty),
token::NtLiteral(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => { token::NtMeta(item) => {
let AttrItem { path, args, tokens } = item.deref_mut(); let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
vis.visit_path(path); vis.visit_path(path);
visit_attr_args(args, vis); visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis); visit_lazy_tts(tokens, vis);

View File

@ -1805,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let attr = attr::mk_attr_nested_word( let attr = attr::mk_attr_nested_word(
&self.tcx.sess.psess.attr_id_generator, &self.tcx.sess.psess.attr_id_generator,
AttrStyle::Outer, AttrStyle::Outer,
Safety::Default,
sym::allow, sym::allow,
sym::unreachable_code, sym::unreachable_code,
self.lower_span(span), self.lower_span(span),

View File

@ -905,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let kind = match attr.kind { let kind = match attr.kind {
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr {
item: AttrItem { item: AttrItem {
unsafety: normal.item.unsafety,
path: normal.item.path.clone(), path: normal.item.path.clone(),
args: self.lower_attr_args(&normal.item.args), args: self.lower_attr_args(&normal.item.args),
tokens: None, 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!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is 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 !visitor.features.never_patterns {
if let Some(spans) = spans.get(&sym::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::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::comments::{Comment, CommentStyle}; 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::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
use rustc_ast::{GenericArg, GenericBound, SelfKind}; use rustc_ast::{GenericArg, GenericBound, SelfKind};
use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
@ -249,6 +249,7 @@ pub fn print_crate<'a>(
let fake_attr = attr::mk_attr_nested_word( let fake_attr = attr::mk_attr_nested_word(
g, g,
ast::AttrStyle::Inner, ast::AttrStyle::Inner,
Safety::Default,
sym::feature, sym::feature,
sym::prelude_import, sym::prelude_import,
DUMMY_SP, DUMMY_SP,
@ -259,7 +260,13 @@ pub fn print_crate<'a>(
// root, so this is not needed, and actually breaks things. // root, so this is not needed, and actually breaks things.
if edition.is_rust_2015() { if edition.is_rust_2015() {
// `#![no_std]` // `#![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); 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 builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
.suggestion = remove the value .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 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 .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 .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 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, Ok(ai) => ai,
Err(err) => { Err(err) => {
err.emit(); err.emit();
@ -33,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
krate.attrs.push(mk_attr( krate.attrs.push(mk_attr(
&psess.attr_id_generator, &psess.attr_id_generator,
AttrStyle::Inner, AttrStyle::Inner,
unsafety,
path, path,
args, args,
start_span.to(end_span), start_span.to(end_span),

View File

@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval;
use crate::errors; use crate::errors;
use rustc_ast as ast; 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::{ use rustc_expand::base::{
Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
}; };
@ -60,6 +60,7 @@ impl MultiItemModifier for Expander {
// Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the
// paths. // paths.
report_path_args(sess, meta); report_path_args(sess, meta);
report_unsafe_args(sess, meta);
meta.path.clone() meta.path.clone()
}) })
.map(|path| DeriveResolution { .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, pub(crate) span: Span,
} }
#[derive(Diagnostic)]
#[diag(builtin_macros_derive_unsafe_path)]
pub(crate) struct DeriveUnsafePath {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(builtin_macros_no_default_variant)] #[diag(builtin_macros_no_default_variant)]
#[help] #[help]

View File

@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
let allow_dead_code = attr::mk_attr_nested_word( let allow_dead_code = attr::mk_attr_nested_word(
&self.sess.psess.attr_id_generator, &self.sess.psess.attr_id_generator,
ast::AttrStyle::Outer, ast::AttrStyle::Outer,
ast::Safety::Default,
sym::allow, sym::allow,
sym::dead_code, sym::dead_code,
self.def_site, self.def_site,

View File

@ -666,7 +666,7 @@ impl<'a> ExtCtxt<'a> {
// Builds `#[name]`. // Builds `#[name]`.
pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute { pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator; 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]`. // Builds `#[name = val]`.
@ -674,12 +674,26 @@ impl<'a> ExtCtxt<'a> {
// Note: `span` is used for both the identifier and the value. // 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 { pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator; 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)]`. // Builds `#[outer(inner)]`.
pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute { pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute {
let g = &self.sess.psess.attr_id_generator; 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 { if let SyntaxExtensionKind::Derive(..) = ext {
self.gate_proc_macro_input(&item); 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) { let items = match expander.expand(self.cx, span, &meta, item, is_const) {
ExpandResult::Ready(items) => items, ExpandResult::Ready(items) => items,
ExpandResult::Retry(item) => { ExpandResult::Retry(item) => {

View File

@ -59,6 +59,16 @@ pub enum AttributeType {
CrateLevel, 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)] #[derive(Clone, Copy)]
pub enum AttributeGate { pub enum AttributeGate {
/// Is gated by a given feature gate, reason /// Is gated by a given feature gate, reason
@ -172,11 +182,23 @@ macro_rules! template {
} }
macro_rules! ungated { 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 $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
type_: $typ, type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
gate: Ungated, gate: Ungated,
duplicates: $duplicates, duplicates: $duplicates,
@ -185,11 +207,34 @@ macro_rules! ungated {
} }
macro_rules! gated { 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 $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
type_: $typ, type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
@ -200,6 +245,7 @@ macro_rules! gated {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
type_: $typ, type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
@ -228,6 +274,7 @@ macro_rules! rustc_attr {
name: sym::$attr, name: sym::$attr,
encode_cross_crate: $encode_cross_crate, encode_cross_crate: $encode_cross_crate,
type_: $typ, type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), 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. /// Otherwise, it can only be used in the local crate.
pub encode_cross_crate: EncodeCrossCrate, pub encode_cross_crate: EncodeCrossCrate,
pub type_: AttributeType, pub type_: AttributeType,
pub safety: AttributeSafety,
pub template: AttributeTemplate, pub template: AttributeTemplate,
pub duplicates: AttributeDuplicates, pub duplicates: AttributeDuplicates,
pub gate: AttributeGate, pub gate: AttributeGate,
@ -375,9 +423,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
@ -486,11 +534,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
gated!( gated!(
ffi_pure, Normal, template!(Word), WarnFollowing, unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(ffi_pure) EncodeCrossCrate::No, experimental!(ffi_pure)
), ),
gated!( gated!(
ffi_const, Normal, template!(Word), WarnFollowing, unsafe ffi_const, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(ffi_const) EncodeCrossCrate::No, experimental!(ffi_const)
), ),
gated!( gated!(
@ -850,6 +898,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
encode_cross_crate: EncodeCrossCrate::Yes, encode_cross_crate: EncodeCrossCrate::Yes,
type_: Normal, type_: Normal,
safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"), template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing, duplicates: ErrorFollowing,
gate: Gated( 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>> = pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
LazyLock::new(|| { LazyLock::new(|| {
let mut map = FxHashMap::default(); 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::AttributeDuplicates;
pub use builtin_attrs::{ pub use builtin_attrs::{
deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name,
is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType,
GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
}; };
pub use removed::REMOVED_FEATURES; pub use removed::REMOVED_FEATURES;
pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_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)), (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
/// Allows unnamed fields of struct and union type /// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)), (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. /// Allows unsafe on extern declarations and safety qualifiers over internal items.
(unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)),
/// Allows unsized fn parameters. /// 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 { 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 /// 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::attr;
use rustc_ast::token::{self, Delimiter}; use rustc_ast::token::{self, Delimiter};
use rustc_errors::{codes::*, Diag, PResult}; 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 thin_vec::ThinVec;
use tracing::debug; use tracing::debug;
@ -252,9 +252,23 @@ impl<'a> Parser<'a> {
maybe_whole!(self, NtMeta, |attr| attr.into_inner()); maybe_whole!(self, NtMeta, |attr| attr.into_inner());
let do_parse = |this: &mut Self| { 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 path = this.parse_path(PathStyle::Mod)?;
let args = this.parse_attr_args()?; 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 // Attr items don't have attributes
if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) } 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 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 path = self.parse_path(PathStyle::Mod)?;
let kind = self.parse_meta_item_kind()?; let kind = self.parse_meta_item_kind()?;
if is_unsafe {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
}
let span = lo.to(self.prev_token.span); 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> { pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {

View File

@ -130,14 +130,14 @@ pub enum AttemptLocalParseRecovery {
} }
impl AttemptLocalParseRecovery { impl AttemptLocalParseRecovery {
pub fn yes(&self) -> bool { pub(super) fn yes(&self) -> bool {
match self { match self {
AttemptLocalParseRecovery::Yes => true, AttemptLocalParseRecovery::Yes => true,
AttemptLocalParseRecovery::No => false, AttemptLocalParseRecovery::No => false,
} }
} }
pub fn no(&self) -> bool { pub(super) fn no(&self) -> bool {
match self { match self {
AttemptLocalParseRecovery::Yes => false, AttemptLocalParseRecovery::Yes => false,
AttemptLocalParseRecovery::No => true, 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, &mut self,
lo: Span, lo: Span,
s: BlockCheckMode, 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 /// 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 /// case, we emit an error and try to suggest enclosing a const argument in braces if it looks
/// like the user has forgotten them. /// like the user has forgotten them.
pub fn handle_ambiguous_unbraced_const_arg( pub(super) fn handle_ambiguous_unbraced_const_arg(
&mut self, &mut self,
args: &mut ThinVec<AngleBracketedArg>, args: &mut ThinVec<AngleBracketedArg>,
) -> PResult<'a, bool> { ) -> PResult<'a, bool> {
@ -2500,7 +2500,7 @@ impl<'a> Parser<'a> {
/// - Single-segment paths (i.e. standalone generic const parameters). /// - Single-segment paths (i.e. standalone generic const parameters).
/// All other expressions that can be parsed will emit an error suggesting the expression be /// All other expressions that can be parsed will emit an error suggesting the expression be
/// wrapped in braces. /// 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 start = self.token.span;
let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| {
err.span_label( err.span_label(
@ -2559,7 +2559,7 @@ impl<'a> Parser<'a> {
Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) 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, &mut self,
ty_generics: Option<&Generics>, ty_generics: Option<&Generics>,
) -> PResult<'a, Option<GenericArg>> { ) -> 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 /// 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 /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion
/// if we think that the resulting expression would be well formed. /// 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) let is_op_or_dot = AssocOp::from_token(&self.token)
.and_then(|op| { .and_then(|op| {
if let AssocOp::Greater 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 /// 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( err.multipart_suggestion(
"expressions must be enclosed in braces to be used as const generic \ "expressions must be enclosed in braces to be used as const generic \
arguments", arguments",
@ -2961,7 +2965,7 @@ impl<'a> Parser<'a> {
/// * `=====` /// * `=====`
/// * `<<<<<` /// * `<<<<<`
/// ///
pub fn is_vcs_conflict_marker( pub(super) fn is_vcs_conflict_marker(
&mut self, &mut self,
long_kind: &TokenKind, long_kind: &TokenKind,
short_kind: &TokenKind, short_kind: &TokenKind,
@ -2981,14 +2985,14 @@ impl<'a> Parser<'a> {
None 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() { if let Err(err) = self.err_vcs_conflict_marker() {
err.emit(); err.emit();
FatalError.raise(); 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) let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt)
else { else {
return Ok(()); return Ok(());

View File

@ -431,7 +431,7 @@ impl<'a> Parser<'a> {
/// The method does not advance the current token. /// The method does not advance the current token.
/// ///
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. /// 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()) { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) {
// When parsing const expressions, stop parsing when encountering `>`. // 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 // At this point we've consumed something like `expr.` and `self.token` holds the token
// after the dot. // after the dot.
match self.token.uninterpolate().kind { match self.token.uninterpolate().kind {

View File

@ -2265,7 +2265,7 @@ pub(crate) struct FnParseMode {
/// to true. /// to true.
/// * The span is from Edition 2015. In particular, you can get a /// * The span is from Edition 2015. In particular, you can get a
/// 2015 span inside a 2021 crate using macros. /// 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 /// If this flag is set to `true`, then plain, semicolon-terminated function
/// prototypes are not allowed here. /// 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 /// 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 /// definition or extern block. Within an impl block or a module, it should
/// always be set to true. /// always be set to true.
pub req_body: bool, pub(super) req_body: bool,
} }
/// Parsing of functions and methods. /// Parsing of functions and methods.

View File

@ -11,14 +11,13 @@ mod stmt;
mod ty; mod ty;
use crate::lexer::UnmatchedDelim; use crate::lexer::UnmatchedDelim;
pub use attr_wrapper::AttrWrapper; use attr_wrapper::AttrWrapper;
pub use diagnostics::AttemptLocalParseRecovery; pub use diagnostics::AttemptLocalParseRecovery;
pub(crate) use expr::ForbiddenLetReason; pub(crate) use expr::ForbiddenLetReason;
pub(crate) use item::FnParseMode; pub(crate) use item::FnParseMode;
pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
pub use path::PathStyle; use path::PathStyle;
use core::fmt;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; 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::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use std::ops::Range; use std::ops::Range;
use std::{mem, slice}; use std::{fmt, mem, slice};
use thin_vec::ThinVec; use thin_vec::ThinVec;
use tracing::debug; use tracing::debug;
@ -146,7 +145,7 @@ pub struct Parser<'a> {
/// The current token. /// The current token.
pub token: Token, pub token: Token,
/// The spacing for the current token. /// The spacing for the current token.
pub token_spacing: Spacing, token_spacing: Spacing,
/// The previous token. /// The previous token.
pub prev_token: Token, pub prev_token: Token,
pub capture_cfg: bool, pub capture_cfg: bool,
@ -187,7 +186,7 @@ pub struct Parser<'a> {
current_closure: Option<ClosureSpans>, current_closure: Option<ClosureSpans>,
/// Whether the parser is allowed to do recovery. /// Whether the parser is allowed to do recovery.
/// This is disabled when parsing macro arguments, see #103534 /// 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 // 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. /// Stores span information about a closure.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ClosureSpans { struct ClosureSpans {
pub whole_closure: Span, whole_closure: Span,
pub closing_pipe: Span, closing_pipe: Span,
pub body: Span, body: Span,
} }
/// Indicates a range of tokens that should be replaced by /// 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). /// the first macro inner attribute to invoke a proc-macro).
/// When create a `TokenStream`, the inner attributes get inserted /// When create a `TokenStream`, the inner attributes get inserted
/// into the proper place in the token stream. /// 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, /// Controls how we capture tokens. Capturing can be expensive,
/// so we try to avoid performing capturing in cases where /// so we try to avoid performing capturing in cases where
/// we will never need an `AttrTokenStream`. /// we will never need an `AttrTokenStream`.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Capturing { enum Capturing {
/// We aren't performing any capturing - this is the default mode. /// We aren't performing any capturing - this is the default mode.
No, No,
/// We are capturing tokens /// We are capturing tokens
@ -374,13 +373,13 @@ pub enum FollowedByType {
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Trailing { enum Trailing {
No, No,
Yes, Yes,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TokenDescription { pub(super) enum TokenDescription {
ReservedIdentifier, ReservedIdentifier,
Keyword, Keyword,
ReservedKeyword, ReservedKeyword,
@ -388,7 +387,7 @@ pub enum TokenDescription {
} }
impl TokenDescription { impl TokenDescription {
pub fn from_token(token: &Token) -> Option<Self> { pub(super) fn from_token(token: &Token) -> Option<Self> {
match token.kind { match token.kind {
_ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier), _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier),
_ if token.is_used_keyword() => Some(TokenDescription::Keyword), _ 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, /// Expect next token to be edible or inedible token. If edible,
/// then consume it; if inedible, then return without consuming /// then consume it; if inedible, then return without consuming
/// anything. Signal a fatal error if next token is unexpected. /// anything. Signal a fatal error if next token is unexpected.
pub fn expect_one_of( fn expect_one_of(
&mut self, &mut self,
edible: &[TokenKind], edible: &[TokenKind],
inedible: &[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 /// 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. /// which using the normal eat method could introduce in some cases.
#[inline] #[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); let is_present = self.check_noexpect(tok);
if is_present { if is_present {
self.bump() 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, &mut self,
f: impl FnOnce(&mut Self) -> PResult<'a, R>, f: impl FnOnce(&mut Self) -> PResult<'a, R>,
) -> 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 // Debug view of the parser's token stream, up to `{lookahead}` tokens.
pub fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { // Only used when debugging.
#[allow(unused)]
pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ {
struct DebugParser<'dbg> { struct DebugParser<'dbg> {
parser: &'dbg Parser<'dbg>, parser: &'dbg Parser<'dbg>,
lookahead: usize, lookahead: usize,
@ -1618,7 +1619,7 @@ pub(crate) fn make_unclosed_delims_error(
/// is then 'parsed' to build up an `AttrTokenStream` with nested /// is then 'parsed' to build up an `AttrTokenStream` with nested
/// `AttrTokenTree::Delimited` tokens. /// `AttrTokenTree::Delimited` tokens.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum FlatToken { enum FlatToken {
/// A token - this holds both delimiter (e.g. '{' and '}') /// A token - this holds both delimiter (e.g. '{' and '}')
/// and non-delimiter tokens /// and non-delimiter tokens
Token(Token), Token(Token),

View File

@ -21,14 +21,12 @@ impl MutVisitor for ToZzIdentMutVisitor {
} }
} }
// Maybe add to `expand.rs`. macro_rules! assert_matches_codepattern {
macro_rules! assert_pred { ($a:expr , $b:expr) => {{
($pred:expr, $predname:expr, $a:expr , $b:expr) => {{
let pred_val = $pred;
let a_val = $a; let a_val = $a;
let b_val = $b; let b_val = $b;
if !(pred_val(&a_val, &b_val)) { if !matches_codepattern(&a_val, &b_val) {
panic!("expected args satisfying {}, got {} and {}", $predname, 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 = let mut krate =
string_to_crate("#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); 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); zz_visitor.visit_crate(&mut krate);
assert_pred!( assert_matches_codepattern!(
matches_codepattern,
"matches_codepattern",
print_crate_items(&krate), print_crate_items(&krate),
"#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string() "#[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(), .to_string(),
); );
zz_visitor.visit_crate(&mut krate); zz_visitor.visit_crate(&mut krate);
assert_pred!( assert_matches_codepattern!(
matches_codepattern,
"matches_codepattern",
print_crate_items(&krate), print_crate_items(&krate),
"macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string() "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. /// Specifies how to parse a path.
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
pub enum PathStyle { pub(super) enum PathStyle {
/// In some contexts, notably in expressions, paths with generic arguments are ambiguous /// In some contexts, notably in expressions, paths with generic arguments are ambiguous
/// with something else. For example, in expressions `segment < ....` can be interpreted /// with something else. For example, in expressions `segment < ....` can be interpreted
/// as a comparison and `segment ( ....` can be interpreted as a function call. /// 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. /// 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. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
// Public for rustfmt usage. // 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| { Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| {
e.emit(); e.emit();
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); 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. /// Parse a type suitable for a field definition.
/// The difference from `parse_ty` is that this version /// The difference from `parse_ty` is that this version
/// allows anonymous structs and unions. /// 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() { if self.can_begin_anon_struct_or_union() {
self.parse_anon_struct_or_union() self.parse_anon_struct_or_union()
} else { } else {

View File

@ -25,15 +25,21 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
match attr_info { match attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes. // `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { 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 => { _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => {
// All key-value attributes are restricted to meta-item syntax. // All key-value attributes are restricted to meta-item syntax.
parse_meta(psess, attr) match parse_meta(psess, attr) {
.map_err(|err| { Ok(_) => {}
Err(err) => {
err.emit(); 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> { pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
let item = attr.get_normal_item(); let item = attr.get_normal_item();
Ok(MetaItem { Ok(MetaItem {
unsafety: item.unsafety,
span: attr.span, span: attr.span,
path: item.path.clone(), path: item.path.clone(),
kind: match &item.args { 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 { if let Delimiter::Parenthesis = delim {
return; 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 { if let Delimiter::Parenthesis = delim {
return; 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( pub fn check_builtin_meta_item(
psess: &ParseSess, psess: &ParseSess,
meta: &MetaItem, meta: &MetaItem,

View File

@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level =
passes_invalid_attr_at_crate_level_item = passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind} 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 = `{$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 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_data_structures::fx::FxHashMap;
use rustc_errors::StashKey; use rustc_errors::StashKey;
use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; 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::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir}; use rustc_hir::{self as hir};
@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
let mut seen = FxHashMap::default(); let mut seen = FxHashMap::default();
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs { for attr in attrs {
self.check_unsafe_attr(attr);
match attr.path().as_slice() { match attr.path().as_slice() {
[sym::diagnostic, sym::do_not_recommend] => { [sym::diagnostic, sym::do_not_recommend] => {
self.check_do_not_recommend(attr.span, hir_id, target) self.check_do_not_recommend(attr.span, hir_id, target)
@ -308,6 +312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
true 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 /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
fn check_diagnostic_on_unimplemented( fn check_diagnostic_on_unimplemented(
&self, &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::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy::Level; use rustc_middle::middle::privacy::Level;
use rustc_middle::query::Providers; 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_middle::{bug, span_bug};
use rustc_session::lint; use rustc_session::lint;
use rustc_session::lint::builtin::DEAD_CODE; 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 if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
&& let Res::Def(def_kind, def_id) = path.res && let Res::Def(def_kind, def_id) = path.res
&& def_id.is_local() && def_id.is_local()
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
{ {
tcx.visibility(def_id).is_public() return match def_kind {
} else { DefKind::Enum | DefKind::Union => {
true 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]` /// 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(..)) if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
.ty_and_all_fields_are_public
{ {
// skip methods of private ty, // skip impl-items of non pure pub ty,
// they would be solved in `solve_rest_impl_items` // cause we don't know the ty is constructed or not,
// check these later in `solve_rest_impl_items`
continue; continue;
} }
@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
&& let Some(local_def_id) = def_id.as_local() && let Some(local_def_id) = def_id.as_local()
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) && 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 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() && 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 // 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_id) && self.live_symbols.contains(&local_def_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() .iter()
.filter_map(|def_id| def_id.as_local()); .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 // And we access the Map here to get HirId from LocalDefId
for local_def_id in local_def_ids { for local_def_id in local_def_ids {
@ -763,18 +813,20 @@ fn check_item<'tcx>(
// for trait impl blocks, // for trait impl blocks,
// mark the method live if the self_ty is public, // mark the method live if the self_ty is public,
// or the method is public and may construct self // or the method is public and may construct self
if of_trait if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy)
&& (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) || tcx.visibility(local_def_id).is_public()
|| tcx.visibility(local_def_id).is_public() && (ty_and_all_fields_are_public || may_construct_self)
&& (ty_is_pub || 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)); worklist.push((local_def_id, ComesFromAllowExpect::No));
} else if let Some(comes_from_allow) = } else if let Some(comes_from_allow) =
has_allow_dead_code_or_lang_attr(tcx, local_def_id) has_allow_dead_code_or_lang_attr(tcx, local_def_id)
{ {
worklist.push((local_def_id, comes_from_allow)); worklist.push((local_def_id, comes_from_allow));
} else if of_trait { } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
// private method || public method not constructs self // private impl items of traits || public impl items not constructs self
unsolved_impl_items.push((id, local_def_id)); unsolved_impl_items.push((id, local_def_id));
} }
} }
@ -841,6 +893,14 @@ fn create_and_seed_worklist(
effective_vis effective_vis
.is_public_at_level(Level::Reachable) .is_public_at_level(Level::Reachable)
.then_some(id) .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)) .map(|id| (id, ComesFromAllowExpect::No))
}) })
// Seed entry point // 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)) || (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) { 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 }) if matches!(def_kind, DefKind::Impl { of_trait: true })
&& tcx.def_kind(def_id) == DefKind::AssocFn && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn)
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) != 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; continue;
} }

View File

@ -4,7 +4,7 @@ use std::{
}; };
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use rustc_ast::Label; use rustc_ast::{ast, Label};
use rustc_errors::{ use rustc_errors::{
codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic,
@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel {
pub item: Option<ItemFollowingInnerAttr>, 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)] #[derive(Clone, Copy)]
pub struct ItemFollowingInnerAttr { pub struct ItemFollowingInnerAttr {
pub span: Span, pub span: Span,

View File

@ -1962,6 +1962,7 @@ symbols! {
unreachable_display, unreachable_display,
unreachable_macro, unreachable_macro,
unrestricted_attribute_tokens, unrestricted_attribute_tokens,
unsafe_attributes,
unsafe_block_in_unsafe_fn, unsafe_block_in_unsafe_fn,
unsafe_cell, unsafe_cell,
unsafe_cell_raw_get, unsafe_cell_raw_get,

View File

@ -23,7 +23,6 @@
#![feature(extract_if)] #![feature(extract_if)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(option_take_if)]
#![feature(never_type)] #![feature(never_type)]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![recursion_limit = "512"] // For rustdoc #![recursion_limit = "512"] // For rustdoc

View File

@ -1216,7 +1216,6 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
/// Basic usage: /// Basic usage:
/// ///
/// ``` /// ```
/// #![feature(binary_heap_as_slice)]
/// use std::collections::BinaryHeap; /// use std::collections::BinaryHeap;
/// use std::io::{self, Write}; /// use std::io::{self, Write};
/// ///
@ -1225,7 +1224,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> {
/// io::sink().write(heap.as_slice()).unwrap(); /// io::sink().write(heap.as_slice()).unwrap();
/// ``` /// ```
#[must_use] #[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] { pub fn as_slice(&self) -> &[T] {
self.data.as_slice() self.data.as_slice()
} }

View File

@ -24,7 +24,6 @@
#![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_into_iter_sorted)]
#![feature(binary_heap_drain_sorted)] #![feature(binary_heap_drain_sorted)]
#![feature(slice_ptr_get)] #![feature(slice_ptr_get)]
#![feature(binary_heap_as_slice)]
#![feature(inplace_iteration)] #![feature(inplace_iteration)]
#![feature(iter_advance_by)] #![feature(iter_advance_by)]
#![feature(iter_next_chunk)] #![feature(iter_next_chunk)]

View File

@ -1708,8 +1708,6 @@ impl<T> Option<T> {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(option_take_if)]
///
/// let mut x = Some(42); /// let mut x = Some(42);
/// ///
/// let prev = x.take_if(|v| if *v == 42 { /// let prev = x.take_if(|v| if *v == 42 {
@ -1726,7 +1724,7 @@ impl<T> Option<T> {
/// assert_eq!(prev, Some(43)); /// assert_eq!(prev, Some(43));
/// ``` /// ```
#[inline] #[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> pub fn take_if<P>(&mut self, predicate: P) -> Option<T>
where where
P: FnOnce(&mut T) -> bool, 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: 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 If you need to override generated functions or types then add them to
`library/std/src/sys/pal/windows/c.rs`. `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::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
use crate::core::config::TargetSelection; use crate::core::config::TargetSelection;
use crate::utils::channel::GitInfo; use crate::utils::channel::GitInfo;
use crate::utils::exec::BootstrapCommand;
use crate::utils::helpers::output; use crate::utils::helpers::output;
use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::utils::helpers::{add_dylib_path, exe, t};
use crate::Compiler; use crate::Compiler;
@ -110,9 +109,8 @@ impl Step for ToolBuild {
&self.target, &self.target,
); );
let mut cargo = Command::from(cargo);
// we check this below // 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( builder.save_toolstate(
tool, tool,

View File

@ -213,21 +213,39 @@ The valid emit kinds are:
`CRATE_NAME.o`. `CRATE_NAME.o`.
The output filename can be set with the [`-o` flag](#option-o-output). A 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` suffix may be added to the filename with the
flag](codegen-options/index.md#extra-filename). The files are written to the [`-C extra-filename` flag](codegen-options/index.md#extra-filename).
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`, Output files are written to the current directory unless the
which takes precedence over the `-o` flag. [`--out-dir` flag](#option-out-dir) is used.
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.
[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html [LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
[LLVM IR]: https://llvm.org/docs/LangRef.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> <a id="option-print"></a>
## `--print`: print compiler information ## `--print`: print compiler information

View File

@ -1,6 +1,6 @@
use super::*; 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::create_default_session_globals_then;
use rustc_span::symbol::{kw, Ident}; use rustc_span::symbol::{kw, Ident};
use rustc_span::DUMMY_SP; 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 { fn dummy_meta_item_word(name: &str) -> MetaItem {
MetaItem { MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(name)), path: Path::from_ident(Ident::from_str(name)),
kind: MetaItemKind::Word, kind: MetaItemKind::Word,
span: DUMMY_SP, 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 { fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem {
let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP };
MetaItem { MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(name)), path: Path::from_ident(Ident::from_str(name)),
kind: MetaItemKind::NameValue(lit), kind: MetaItemKind::NameValue(lit),
span: DUMMY_SP, 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 { macro_rules! dummy_meta_item_list {
($name:ident, [$($list:ident),* $(,)?]) => { ($name:ident, [$($list:ident),* $(,)?]) => {
MetaItem { MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(stringify!($name))), path: Path::from_ident(Ident::from_str(stringify!($name))),
kind: MetaItemKind::List(thin_vec![ kind: MetaItemKind::List(thin_vec![
$( $(
@ -48,6 +51,7 @@ macro_rules! dummy_meta_item_list {
($name:ident, [$($list:expr),* $(,)?]) => { ($name:ident, [$($list:expr),* $(,)?]) => {
MetaItem { MetaItem {
unsafety: Safety::Default,
path: Path::from_ident(Ident::from_str(stringify!($name))), path: Path::from_ident(Ident::from_str(stringify!($name))),
kind: MetaItemKind::List(thin_vec![ kind: MetaItemKind::List(thin_vec![
$( $(

View File

@ -3515,7 +3515,6 @@ impl<'test> TestCx<'test> {
.arg(&self.testpaths.file.join("rmake.rs")) .arg(&self.testpaths.file.join("rmake.rs"))
.env("TARGET", &self.config.target) .env("TARGET", &self.config.target)
.env("PYTHON", &self.config.python) .env("PYTHON", &self.config.python)
.env("S", &src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id) .env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path)) .env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &rmake_out_dir) .env("TMPDIR", &rmake_out_dir)
@ -3567,7 +3566,7 @@ impl<'test> TestCx<'test> {
.env(dylib_env_var(), &dylib_env_paths) .env(dylib_env_var(), &dylib_env_paths)
.env("TARGET", &self.config.target) .env("TARGET", &self.config.target)
.env("PYTHON", &self.config.python) .env("PYTHON", &self.config.python)
.env("S", &src_root) .env("SOURCE_ROOT", &src_root)
.env("RUST_BUILD_STAGE", &self.config.stage_id) .env("RUST_BUILD_STAGE", &self.config.stage_id)
.env("RUSTC", cwd.join(&self.config.rustc_path)) .env("RUSTC", cwd.join(&self.config.rustc_path))
.env("TMPDIR", &rmake_out_dir) .env("TMPDIR", &rmake_out_dir)

View File

@ -89,7 +89,7 @@ pub fn htmldocck() -> Command {
/// Path to the root rust-lang/rust source checkout. /// Path to the root rust-lang/rust source checkout.
pub fn source_root() -> PathBuf { pub fn source_root() -> PathBuf {
env_var("S").into() env_var("SOURCE_ROOT").into()
} }
/// Construct the static library name based on the platform. /// 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<()> { fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.encoders self.encoders.par_iter_mut().try_for_each(|w| w.write_all(buf))
.par_iter_mut()
.map(|w| w.write_all(buf))
.collect::<std::io::Result<Vec<()>>>()?;
Ok(())
} }
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {
self.encoders.par_iter_mut().map(|w| w.flush()).collect::<std::io::Result<Vec<()>>>()?; self.encoders.par_iter_mut().try_for_each(Write::flush)
Ok(())
} }
} }
impl Encoder for CombinedEncoder { impl Encoder for CombinedEncoder {
fn finish(self: Box<Self>) -> Result<(), Error> { fn finish(self: Box<Self>) -> Result<(), Error> {
self.encoders.into_par_iter().map(|e| e.finish()).collect::<Result<Vec<()>, Error>>()?; self.encoders.into_par_iter().try_for_each(Encoder::finish)
Ok(())
} }
} }

View File

@ -22,16 +22,16 @@ impl<T> Struct<T> {
} }
} }
pub struct LifeTimeOnly<'a> { pub struct _LifeTimeOnly<'a> {
_a: &'a u32, _a: &'a u32,
} }
impl<'a> LifeTimeOnly<'a> { impl<'a> _LifeTimeOnly<'a> {
//~ MONO_ITEM fn LifeTimeOnly::<'_>::foo //~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo
pub fn foo(&self) {} pub fn foo(&self) {}
//~ MONO_ITEM fn LifeTimeOnly::<'_>::bar //~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar
pub fn bar(&'a self) {} pub fn bar(&'a self) {}
//~ MONO_ITEM fn LifeTimeOnly::<'_>::baz //~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz
pub fn baz<'b>(&'b self) {} pub fn baz<'b>(&'b self) {}
pub fn non_instantiated<T>(&self) {} pub fn non_instantiated<T>(&self) {}

View File

@ -5,44 +5,44 @@
use std::ops::{Add, Deref, Index, IndexMut}; use std::ops::{Add, Deref, Index, IndexMut};
pub struct Indexable { pub struct _Indexable {
data: [u8; 3], data: [u8; 3],
} }
impl Index<usize> for Indexable { impl Index<usize> for _Indexable {
type Output = u8; 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 { fn index(&self, index: usize) -> &Self::Output {
if index >= 3 { &self.data[0] } else { &self.data[index] } if index >= 3 { &self.data[0] } else { &self.data[index] }
} }
} }
impl IndexMut<usize> for Indexable { impl IndexMut<usize> for _Indexable {
//~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut //~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut
fn index_mut(&mut self, index: usize) -> &mut Self::Output { fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= 3 { &mut self.data[0] } else { &mut self.data[index] } 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>::eq
//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne //~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct Equatable(u32); pub struct _Equatable(u32);
impl Add<u32> for Equatable { impl Add<u32> for _Equatable {
type Output = u32; 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 { fn add(self, rhs: u32) -> u32 {
self.0 + rhs self.0 + rhs
} }
} }
impl Deref for Equatable { impl Deref for _Equatable {
type Target = u32; 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 { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }

View File

@ -5,7 +5,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use run_make_support::{aux_build, rustc}; use run_make_support::{aux_build, rustc, source_root};
fn main() { fn main() {
aux_build().input("stable.rs").emit("metadata").run(); 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(); rustc().input("main.rs").emit("metadata").extern_("stable", &stable_path).command_output();
let stderr = String::from_utf8_lossy(&output.stderr); 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()); let expected_string = format!("stable since {}", version.trim());
assert!(stderr.contains(&expected_string)); 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. // Get all items and split generic vs monomorphic items.
let (generic, mono): (Vec<_>, Vec<_>) = let (generic, mono): (Vec<_>, Vec<_>) =
items.into_iter().partition(|item| item.requires_monomorphization()); 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"); assert_eq!(generic.len(), 2, "Expected 2 generic functions");
// For all monomorphic items, get the correspondent instances. // 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) { for term in body.blocks.iter().map(|bb| &bb.terminator) {
match &term.kind { match &term.kind {
Call { func, .. } => { 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 RigidTy::FnDef(def, args) = ty else { unreachable!() };
let instance = Instance::resolve(def, &args).unwrap(); let instance = Instance::resolve(def, &args).unwrap();
let mangled_name = instance.mangled_name(); let mangled_name = instance.mangled_name();
@ -102,6 +103,9 @@ fn generate_input(path: &str) -> std::io::Result<()> {
write!( write!(
file, file,
r#" r#"
struct Foo(());
pub fn ty_param<T>(t: &T) -> T where T: Clone {{ pub fn ty_param<T>(t: &T) -> T where T: Clone {{
t.clone() t.clone()
}} }}
@ -116,6 +120,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
}} }}
pub fn monomorphic() {{ pub fn monomorphic() {{
Foo(());
let v = vec![10]; let v = vec![10];
let dup = ty_param(&v); let dup = ty_param(&v);
assert_eq!(v, dup); 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; extern crate re_rebalance_coherence_lib as lib;
use lib::*; use lib::*;
#[allow(dead_code)]
struct Oracle; struct Oracle;
impl Backend for Oracle {} impl Backend for Oracle {}
impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {} impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}

View File

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

View File

@ -16,7 +16,8 @@ impl BlockCipher for BarCipher {
const BLOCK_SIZE: usize = 32; 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>() pub fn test<C: BlockCipher, const M: usize>()
where where

View File

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

View File

@ -1,9 +1,9 @@
#![forbid(dead_code)] #![forbid(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct Whatever { pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
pub field0: (), pub field0: (),
field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read field1: (),
field2: (), field2: (),
field3: (), field3: (),
field4: (), field4: (),

View File

@ -1,19 +1,9 @@
error: fields `field1`, `field2`, `field3`, and `field4` are never read error: struct `Whatever` is never constructed
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5 --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
| |
LL | pub struct Whatever { 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 note: the lint level is defined here
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 --> $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!() } fn dummy(&self, t: T) -> T { panic!() }
} }
#[allow(dead_code)]
pub struct MyContainer<'a, T:'a> { pub struct MyContainer<'a, T:'a> {
foos: Vec<&'a (dyn MyTrait<T>+'a)> , foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
} }

View File

@ -46,11 +46,10 @@ struct SemiUsedStruct;
impl SemiUsedStruct { impl SemiUsedStruct {
fn la_la_la() {} fn la_la_la() {}
} }
struct StructUsedAsField; struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed
pub struct StructUsedInEnum; pub struct StructUsedInEnum;
struct StructUsedInGeneric; struct StructUsedInGeneric;
pub struct PubStruct2 { pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed
#[allow(dead_code)]
struct_used_as_field: *const StructUsedAsField struct_used_as_field: *const StructUsedAsField
} }

View File

@ -22,14 +22,26 @@ error: struct `PrivStruct` is never constructed
LL | struct PrivStruct; 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 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 } LL | enum priv_enum { foo2, bar2 }
| ^^^^^^^^^ | ^^^^^^^^^
error: variant `bar3` is never constructed 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 { LL | enum used_enum {
| --------- variant in this enum | --------- variant in this enum
@ -38,25 +50,25 @@ LL | bar3
| ^^^^ | ^^^^
error: function `priv_fn` is never used 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() { LL | fn priv_fn() {
| ^^^^^^^ | ^^^^^^^
error: function `foo` is never used 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() { LL | fn foo() {
| ^^^ | ^^^
error: function `bar` is never used 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() { LL | fn bar() {
| ^^^ | ^^^
error: function `baz` is never used 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 { LL | fn baz() -> impl Copy {
| ^^^ | ^^^
@ -67,5 +79,5 @@ error: struct `Bar` is never constructed
LL | pub struct Bar; 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. // Regression test for issues #100790 and #106439.
//@ run-rustfix //@ run-rustfix
pub struct Example(#[allow(dead_code)] usize) #[allow(dead_code)]
pub struct Example(usize)
where where
(): Sized; (): Sized;
//~^^^ ERROR where clauses are not allowed before tuple struct bodies //~^^^ ERROR where clauses are not allowed before tuple struct bodies

View File

@ -1,10 +1,11 @@
// Regression test for issues #100790 and #106439. // Regression test for issues #100790 and #106439.
//@ run-rustfix //@ run-rustfix
#[allow(dead_code)]
pub struct Example pub struct Example
where where
(): Sized, (): Sized,
(#[allow(dead_code)] usize); (usize);
//~^^^ ERROR where clauses are not allowed before tuple struct bodies //~^^^ ERROR where clauses are not allowed before tuple struct bodies
struct _Demo struct _Demo

View File

@ -1,23 +1,23 @@
error: where clauses are not allowed before tuple struct bodies 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 LL | pub struct Example
| ------- while parsing this tuple struct | ------- while parsing this tuple struct
LL | / where LL | / where
LL | | (): Sized, LL | | (): Sized,
| |______________^ unexpected where clause | |______________^ unexpected where clause
LL | (#[allow(dead_code)] usize); LL | (usize);
| --------------------------- the struct body | ------- the struct body
| |
help: move the body before the where clause help: move the body before the where clause
| |
LL ~ pub struct Example(#[allow(dead_code)] usize) LL ~ pub struct Example(usize)
LL | where LL | where
LL ~ (): Sized; LL ~ (): Sized;
| |
error: where clauses are not allowed before tuple struct bodies 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 LL | struct _Demo
| ----- while parsing this tuple struct | ----- while parsing this tuple struct

View File

@ -1,6 +1,7 @@
//@ run-rustfix //@ run-rustfix
pub struct T(#[allow(dead_code)] String); #[allow(dead_code)]
pub struct T(String);
//~^ ERROR missing `struct` for struct definition //~^ ERROR missing `struct` for struct definition
fn main() {} fn main() {}

View File

@ -1,6 +1,7 @@
//@ run-rustfix //@ run-rustfix
pub T(#[allow(dead_code)] String); #[allow(dead_code)]
pub T(String);
//~^ ERROR missing `struct` for struct definition //~^ ERROR missing `struct` for struct definition
fn main() {} fn main() {}

View File

@ -1,12 +1,12 @@
error: missing `struct` for struct definition 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 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 error: aborting due to 1 previous error

View File

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

View File

@ -3,8 +3,10 @@
#![allow(unused_variables)] #![allow(unused_variables)]
//@ pretty-expanded FIXME #23616 //@ pretty-expanded FIXME #23616
#[allow(dead_code)]
pub struct Fd(u32); pub struct Fd(u32);
#[allow(dead_code)]
fn foo(a: u32) {} fn foo(a: u32) {}
impl Drop for Fd { impl Drop for Fd {

View File

@ -1,4 +1,5 @@
//@ run-pass //@ run-pass
pub struct Z(#[allow(dead_code)] &'static Z); #[allow(dead_code)]
pub struct Z(&'static Z);
pub fn main() {} pub fn main() {}

View File

@ -1,6 +1,7 @@
//@ run-rustfix //@ run-rustfix
// https://github.com/rust-lang/rust/issues/79076 // https://github.com/rust-lang/rust/issues/79076
#[allow(dead_code)]
#[derive(Clone, Eq)] //~ ERROR [E0277] #[derive(Clone, Eq)] //~ ERROR [E0277]
pub struct Struct<T: std::clone::Clone>(T); pub struct Struct<T: std::clone::Clone>(T);

View File

@ -1,6 +1,7 @@
//@ run-rustfix //@ run-rustfix
// https://github.com/rust-lang/rust/issues/79076 // https://github.com/rust-lang/rust/issues/79076
#[allow(dead_code)]
#[derive(Clone, Eq)] //~ ERROR [E0277] #[derive(Clone, Eq)] //~ ERROR [E0277]
pub struct Struct<T>(T); pub struct Struct<T>(T);

View File

@ -1,11 +1,11 @@
error[E0277]: the trait bound `T: Clone` is not satisfied 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)] LL | #[derive(Clone, Eq)]
| ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq` | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
| |
note: required for `Struct<T>` to implement `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> LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
| ----- ^^^^^^^^^^^^ ^^^^^^^^^ | ----- ^^^^^^^^^^^^ ^^^^^^^^^

View File

@ -1,4 +1,5 @@
//@ run-rustfix //@ run-rustfix
#[allow(dead_code)]
pub struct LipogramCorpora { pub struct LipogramCorpora {
selections: Vec<(char, Option<String>)>, selections: Vec<(char, Option<String>)>,
} }
@ -17,6 +18,7 @@ impl LipogramCorpora {
} }
} }
#[allow(dead_code)]
pub struct LipogramCorpora2 { pub struct LipogramCorpora2 {
selections: Vec<(char, Result<String, String>)>, selections: Vec<(char, Result<String, String>)>,
} }

View File

@ -1,4 +1,5 @@
//@ run-rustfix //@ run-rustfix
#[allow(dead_code)]
pub struct LipogramCorpora { pub struct LipogramCorpora {
selections: Vec<(char, Option<String>)>, selections: Vec<(char, Option<String>)>,
} }
@ -17,6 +18,7 @@ impl LipogramCorpora {
} }
} }
#[allow(dead_code)]
pub struct LipogramCorpora2 { pub struct LipogramCorpora2 {
selections: Vec<(char, Result<String, String>)>, 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 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) { LL | if selection.1.unwrap().contains(selection.0) {
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call | ^^^^^^^^^^^ -------- `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 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) { LL | if selection.1.unwrap().contains(selection.0) {
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call

View File

@ -7,6 +7,7 @@ pub trait Trait2<A> {
fn doit(&self) -> A; fn doit(&self) -> A;
} }
#[allow(dead_code)]
pub struct Impl<A1, A2, A3> { pub struct Impl<A1, A2, A3> {
m1: marker::PhantomData<(A1,A2,A3)>, m1: marker::PhantomData<(A1,A2,A3)>,
/* /*