Skip to content

Commit 044cdf2

Browse files
authored
Rollup merge of rust-lang#145206 - scrabsha:push-uxovoqzrxnlx, r=jdonszelmann
Port `#[custom_mir(..)]` to the new attribute system r? ```@jdonszelmann```
2 parents 25a3df8 + e854013 commit 044cdf2

File tree

15 files changed

+313
-90
lines changed

15 files changed

+313
-90
lines changed

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub(crate) mod no_implicit_prelude;
4343
pub(crate) mod non_exhaustive;
4444
pub(crate) mod path;
4545
pub(crate) mod proc_macro_attrs;
46+
pub(crate) mod prototype;
4647
pub(crate) mod repr;
4748
pub(crate) mod rustc_internal;
4849
pub(crate) mod semantics;
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
//! Attributes that are only used on function prototypes.
2+
3+
use rustc_feature::{AttributeTemplate, template};
4+
use rustc_hir::attrs::{AttributeKind, MirDialect, MirPhase};
5+
use rustc_span::{Span, Symbol, sym};
6+
7+
use super::{AttributeOrder, OnDuplicate};
8+
use crate::attributes::SingleAttributeParser;
9+
use crate::context::{AcceptContext, Stage};
10+
use crate::parser::ArgParser;
11+
12+
pub(crate) struct CustomMirParser;
13+
14+
impl<S: Stage> SingleAttributeParser<S> for CustomMirParser {
15+
const PATH: &[rustc_span::Symbol] = &[sym::custom_mir];
16+
17+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
18+
19+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
20+
21+
const TEMPLATE: AttributeTemplate = template!(List: r#"dialect = "...", phase = "...""#);
22+
23+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
24+
let Some(list) = args.list() else {
25+
cx.expected_list(cx.attr_span);
26+
return None;
27+
};
28+
29+
let mut dialect = None;
30+
let mut phase = None;
31+
let mut failed = false;
32+
33+
for item in list.mixed() {
34+
let Some(meta_item) = item.meta_item() else {
35+
cx.expected_name_value(item.span(), None);
36+
failed = true;
37+
break;
38+
};
39+
40+
if let Some(arg) = meta_item.word_is(sym::dialect) {
41+
extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed);
42+
} else if let Some(arg) = meta_item.word_is(sym::phase) {
43+
extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed);
44+
} else if let Some(word) = meta_item.path().word() {
45+
let word = word.to_string();
46+
cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]);
47+
failed = true;
48+
} else {
49+
cx.expected_name_value(meta_item.span(), None);
50+
failed = true;
51+
};
52+
}
53+
54+
let dialect = parse_dialect(cx, dialect, &mut failed);
55+
let phase = parse_phase(cx, phase, &mut failed);
56+
57+
if failed {
58+
return None;
59+
}
60+
61+
Some(AttributeKind::CustomMir(dialect, phase, cx.attr_span))
62+
}
63+
}
64+
65+
fn extract_value<S: Stage>(
66+
cx: &mut AcceptContext<'_, '_, S>,
67+
key: Symbol,
68+
arg: &ArgParser<'_>,
69+
span: Span,
70+
out_val: &mut Option<(Symbol, Span)>,
71+
failed: &mut bool,
72+
) {
73+
if out_val.is_some() {
74+
cx.duplicate_key(span, key);
75+
*failed = true;
76+
return;
77+
}
78+
79+
let Some(val) = arg.name_value() else {
80+
cx.expected_single_argument(arg.span().unwrap_or(span));
81+
*failed = true;
82+
return;
83+
};
84+
85+
let Some(value_sym) = val.value_as_str() else {
86+
cx.expected_string_literal(val.value_span, Some(val.value_as_lit()));
87+
*failed = true;
88+
return;
89+
};
90+
91+
*out_val = Some((value_sym, val.value_span));
92+
}
93+
94+
fn parse_dialect<S: Stage>(
95+
cx: &mut AcceptContext<'_, '_, S>,
96+
dialect: Option<(Symbol, Span)>,
97+
failed: &mut bool,
98+
) -> Option<(MirDialect, Span)> {
99+
let (dialect, span) = dialect?;
100+
101+
let dialect = match dialect {
102+
sym::analysis => MirDialect::Analysis,
103+
sym::built => MirDialect::Built,
104+
sym::runtime => MirDialect::Runtime,
105+
106+
_ => {
107+
cx.expected_specific_argument(span, vec!["analysis", "built", "runtime"]);
108+
*failed = true;
109+
return None;
110+
}
111+
};
112+
113+
Some((dialect, span))
114+
}
115+
116+
fn parse_phase<S: Stage>(
117+
cx: &mut AcceptContext<'_, '_, S>,
118+
phase: Option<(Symbol, Span)>,
119+
failed: &mut bool,
120+
) -> Option<(MirPhase, Span)> {
121+
let (phase, span) = phase?;
122+
123+
let phase = match phase {
124+
sym::initial => MirPhase::Initial,
125+
sym::post_cleanup => MirPhase::PostCleanup,
126+
sym::optimized => MirPhase::Optimized,
127+
128+
_ => {
129+
cx.expected_specific_argument(span, vec!["initial", "post-cleanup", "optimized"]);
130+
*failed = true;
131+
return None;
132+
}
133+
};
134+
135+
Some((phase, span))
136+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::attributes::path::PathParser as PathAttributeParser;
4343
use crate::attributes::proc_macro_attrs::{
4444
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
4545
};
46+
use crate::attributes::prototype::CustomMirParser;
4647
use crate::attributes::repr::{AlignParser, ReprParser};
4748
use crate::attributes::rustc_internal::{
4849
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -159,6 +160,7 @@ attribute_parsers!(
159160

160161
// tidy-alphabetical-start
161162
Single<CoverageParser>,
163+
Single<CustomMirParser>,
162164
Single<DeprecationParser>,
163165
Single<DummyParser>,
164166
Single<ExportNameParser>,

compiler/rustc_errors/src/diagnostic_impls.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_abi::TargetDataLayoutErrors;
99
use rustc_ast::util::parser::ExprPrecedence;
1010
use rustc_ast_pretty::pprust;
1111
use rustc_hir::RustcVersion;
12+
use rustc_hir::attrs::{MirDialect, MirPhase};
1213
use rustc_macros::Subdiagnostic;
1314
use rustc_span::edition::Edition;
1415
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
@@ -312,6 +313,28 @@ impl IntoDiagArg for ExprPrecedence {
312313
}
313314
}
314315

316+
impl IntoDiagArg for MirDialect {
317+
fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
318+
let arg = match self {
319+
MirDialect::Analysis => "analysis",
320+
MirDialect::Built => "built",
321+
MirDialect::Runtime => "runtime",
322+
};
323+
DiagArgValue::Str(Cow::Borrowed(arg))
324+
}
325+
}
326+
327+
impl IntoDiagArg for MirPhase {
328+
fn into_diag_arg(self, _path: &mut Option<PathBuf>) -> DiagArgValue {
329+
let arg = match self {
330+
MirPhase::Initial => "initial",
331+
MirPhase::PostCleanup => "post-cleanup",
332+
MirPhase::Optimized => "optimized",
333+
};
334+
DiagArgValue::Str(Cow::Borrowed(arg))
335+
}
336+
}
337+
315338
#[derive(Clone)]
316339
pub struct DiagSymbolList<S = Symbol>(Vec<S>);
317340

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ pub enum CfgEntry {
187187
Version(Option<RustcVersion>, Span),
188188
}
189189

190+
#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
191+
#[derive(HashStable_Generic, PrintAttribute)]
192+
pub enum MirDialect {
193+
Analysis,
194+
Built,
195+
Runtime,
196+
}
197+
198+
#[derive(Clone, Copy, Decodable, Debug, Encodable, PartialEq)]
199+
#[derive(HashStable_Generic, PrintAttribute)]
200+
pub enum MirPhase {
201+
Initial,
202+
PostCleanup,
203+
Optimized,
204+
}
205+
190206
/// Represents parsed *built-in* inert attributes.
191207
///
192208
/// ## Overview
@@ -306,6 +322,9 @@ pub enum AttributeKind {
306322
/// Represents `#[coverage(..)]`.
307323
Coverage(Span, CoverageAttrKind),
308324

325+
/// Represents `#[custom_mir]`.
326+
CustomMir(Option<(MirDialect, Span)>, Option<(MirPhase, Span)>, Span),
327+
309328
///Represents `#[rustc_deny_explicit_impl]`.
310329
DenyExplicitImpl(Span),
311330

compiler/rustc_hir/src/attrs/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ impl AttributeKind {
3131
ConstTrait(..) => No,
3232
Coroutine(..) => No,
3333
Coverage(..) => No,
34+
CustomMir(_, _, _) => Yes,
3435
DenyExplicitImpl(..) => No,
3536
Deprecation { .. } => Yes,
3637
DoNotImplementViaObject(..) => No,

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -115,48 +115,6 @@ impl MirPhase {
115115
MirPhase::Runtime(runtime_phase) => (3, 1 + runtime_phase as usize),
116116
}
117117
}
118-
119-
/// Parses a `MirPhase` from a pair of strings. Panics if this isn't possible for any reason.
120-
pub fn parse(dialect: String, phase: Option<String>) -> Self {
121-
match &*dialect.to_ascii_lowercase() {
122-
"built" => {
123-
assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
124-
MirPhase::Built
125-
}
126-
"analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
127-
"runtime" => Self::Runtime(RuntimePhase::parse(phase)),
128-
_ => bug!("Unknown MIR dialect: '{}'", dialect),
129-
}
130-
}
131-
}
132-
133-
impl AnalysisPhase {
134-
pub fn parse(phase: Option<String>) -> Self {
135-
let Some(phase) = phase else {
136-
return Self::Initial;
137-
};
138-
139-
match &*phase.to_ascii_lowercase() {
140-
"initial" => Self::Initial,
141-
"post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
142-
_ => bug!("Unknown analysis phase: '{}'", phase),
143-
}
144-
}
145-
}
146-
147-
impl RuntimePhase {
148-
pub fn parse(phase: Option<String>) -> Self {
149-
let Some(phase) = phase else {
150-
return Self::Initial;
151-
};
152-
153-
match &*phase.to_ascii_lowercase() {
154-
"initial" => Self::Initial,
155-
"post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
156-
"optimized" => Self::Optimized,
157-
_ => bug!("Unknown runtime phase: '{}'", phase),
158-
}
159-
}
160118
}
161119

162120
/// Where a specific `mir::Body` comes from.

compiler/rustc_mir_build/src/builder/custom/mod.rs

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
2020
use rustc_data_structures::fx::FxHashMap;
2121
use rustc_hir::def_id::DefId;
22-
use rustc_hir::{Attribute, HirId};
22+
use rustc_hir::{HirId, attrs};
2323
use rustc_index::{IndexSlice, IndexVec};
24+
use rustc_middle::bug;
2425
use rustc_middle::mir::*;
25-
use rustc_middle::span_bug;
2626
use rustc_middle::thir::*;
2727
use rustc_middle::ty::{self, Ty, TyCtxt};
2828
use rustc_span::Span;
@@ -39,7 +39,8 @@ pub(super) fn build_custom_mir<'tcx>(
3939
return_ty: Ty<'tcx>,
4040
return_ty_span: Span,
4141
span: Span,
42-
attr: &Attribute,
42+
dialect: Option<attrs::MirDialect>,
43+
phase: Option<attrs::MirPhase>,
4344
) -> Body<'tcx> {
4445
let mut body = Body {
4546
basic_blocks: BasicBlocks::new(IndexVec::new()),
@@ -72,7 +73,7 @@ pub(super) fn build_custom_mir<'tcx>(
7273
inlined_parent_scope: None,
7374
local_data: ClearCrossCrate::Set(SourceScopeLocalData { lint_root: hir_id }),
7475
});
75-
body.injection_phase = Some(parse_attribute(attr));
76+
body.injection_phase = Some(parse_attribute(dialect, phase));
7677

7778
let mut pctxt = ParseCtxt {
7879
tcx,
@@ -98,40 +99,38 @@ pub(super) fn build_custom_mir<'tcx>(
9899
body
99100
}
100101

101-
fn parse_attribute(attr: &Attribute) -> MirPhase {
102-
let meta_items = attr.meta_item_list().unwrap();
103-
let mut dialect: Option<String> = None;
104-
let mut phase: Option<String> = None;
105-
106-
// Not handling errors properly for this internal attribute; will just abort on errors.
107-
for nested in meta_items {
108-
let name = nested.name().unwrap();
109-
let value = nested.value_str().unwrap().as_str().to_string();
110-
match name.as_str() {
111-
"dialect" => {
112-
assert!(dialect.is_none());
113-
dialect = Some(value);
114-
}
115-
"phase" => {
116-
assert!(phase.is_none());
117-
phase = Some(value);
118-
}
119-
other => {
120-
span_bug!(
121-
nested.span(),
122-
"Unexpected key while parsing custom_mir attribute: '{}'",
123-
other
124-
);
125-
}
126-
}
127-
}
128-
102+
/// Turns the arguments passed to `#[custom_mir(..)]` into a proper
103+
/// [`MirPhase`]. Panics if this isn't possible for any reason.
104+
fn parse_attribute(dialect: Option<attrs::MirDialect>, phase: Option<attrs::MirPhase>) -> MirPhase {
129105
let Some(dialect) = dialect else {
106+
// Caught during attribute checking.
130107
assert!(phase.is_none());
131108
return MirPhase::Built;
132109
};
133110

134-
MirPhase::parse(dialect, phase)
111+
match dialect {
112+
attrs::MirDialect::Built => {
113+
// Caught during attribute checking.
114+
assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
115+
MirPhase::Built
116+
}
117+
attrs::MirDialect::Analysis => match phase {
118+
None | Some(attrs::MirPhase::Initial) => MirPhase::Analysis(AnalysisPhase::Initial),
119+
120+
Some(attrs::MirPhase::PostCleanup) => MirPhase::Analysis(AnalysisPhase::PostCleanup),
121+
122+
Some(attrs::MirPhase::Optimized) => {
123+
// Caught during attribute checking.
124+
bug!("`optimized` dialect is not compatible with the `analysis` dialect")
125+
}
126+
},
127+
128+
attrs::MirDialect::Runtime => match phase {
129+
None | Some(attrs::MirPhase::Initial) => MirPhase::Runtime(RuntimePhase::Initial),
130+
Some(attrs::MirPhase::PostCleanup) => MirPhase::Runtime(RuntimePhase::PostCleanup),
131+
Some(attrs::MirPhase::Optimized) => MirPhase::Runtime(RuntimePhase::Optimized),
132+
},
133+
}
135134
}
136135

137136
struct ParseCtxt<'a, 'tcx> {

0 commit comments

Comments
 (0)