Skip to content

Commit 8dc84fa

Browse files
committed
Move some functions from rustc_expand to rustc_builtin_macros.
These functions are only used in `rustc_builtin_macros`, so it makes sense for them to live there. This allows them to be changed from `pub` to `pub(crate)`.
1 parent e2d2b1c commit 8dc84fa

File tree

14 files changed

+234
-237
lines changed

14 files changed

+234
-237
lines changed

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ builtin_macros_env_not_unicode = environment variable `{$var}` is not a valid Un
118118
119119
builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
120120
121+
builtin_macros_expected_comma_in_list = expected token: `,`
122+
121123
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
122124
123125
builtin_macros_expected_register_class_or_explicit_register = expected register class or explicit register
@@ -219,12 +221,16 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
219221
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
220222
.help = consider a manual implementation of `Default`
221223
224+
builtin_macros_only_one_argument = {$name} takes 1 argument
225+
222226
builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
223227
224228
builtin_macros_requires_cfg_pattern =
225229
macro requires a cfg-pattern as an argument
226230
.label = cfg-pattern required
227231
232+
builtin_macros_takes_no_arguments = {$name} takes no arguments
233+
228234
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
229235
.label = `{$kind}` because of this
230236

compiler/rustc_builtin_macros/src/asm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::errors;
2+
use crate::util::expr_to_spanned_string;
13
use ast::token::IdentIsRaw;
24
use rustc_ast as ast;
35
use rustc_ast::ptr::P;
@@ -16,8 +18,6 @@ use rustc_span::{ErrorGuaranteed, InnerSpan, Span};
1618
use rustc_target::asm::InlineAsmArch;
1719
use smallvec::smallvec;
1820

19-
use crate::errors;
20-
2121
pub struct AsmArgs {
2222
pub templates: Vec<P<ast::Expr>>,
2323
pub operands: Vec<(ast::InlineAsmOperand, Span)>,

compiler/rustc_builtin_macros/src/compile_error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// The compiler code necessary to support the compile_error! extension.
22

3+
use crate::util::get_single_str_from_tts;
34
use rustc_ast::tokenstream::TokenStream;
4-
use rustc_expand::base::get_single_str_from_tts;
55
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
66
use rustc_span::Span;
77

compiler/rustc_builtin_macros/src/concat.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
use crate::errors;
2+
use crate::util::get_exprs_from_tts;
13
use rustc_ast::tokenstream::TokenStream;
24
use rustc_ast::{ExprKind, LitKind, UnOp};
3-
use rustc_expand::base::get_exprs_from_tts;
45
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
56
use rustc_session::errors::report_lit_error;
67
use rustc_span::symbol::Symbol;
78

8-
use crate::errors;
9-
109
pub fn expand_concat(
1110
cx: &mut ExtCtxt<'_>,
1211
sp: rustc_span::Span,

compiler/rustc_builtin_macros/src/concat_bytes.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1+
use crate::errors;
2+
use crate::util::get_exprs_from_tts;
13
use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
2-
use rustc_expand::base::get_exprs_from_tts;
34
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
45
use rustc_session::errors::report_lit_error;
56
use rustc_span::{ErrorGuaranteed, Span};
67

7-
use crate::errors;
8-
98
/// Emits errors for literal expressions that are invalid inside and outside of an array.
109
fn invalid_type_err(
1110
cx: &ExtCtxt<'_>,

compiler/rustc_builtin_macros/src/env.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@
33
// interface.
44
//
55

6+
use crate::errors;
7+
use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
68
use rustc_ast::token::{self, LitKind};
79
use rustc_ast::tokenstream::TokenStream;
810
use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
9-
use rustc_expand::base::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
1011
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
1112
use rustc_span::symbol::{kw, sym, Ident, Symbol};
1213
use rustc_span::Span;
1314
use std::env;
1415
use std::env::VarError;
1516
use thin_vec::thin_vec;
1617

17-
use crate::errors;
18-
1918
fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
2019
let var = var.as_str();
2120
if let Some(value) = cx.sess.opts.logical_env.get(var) {

compiler/rustc_builtin_macros/src/errors.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,3 +842,26 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
842842
#[primary_span]
843843
pub(crate) span: Span,
844844
}
845+
846+
#[derive(Diagnostic)]
847+
#[diag(builtin_macros_expected_comma_in_list)]
848+
pub(crate) struct ExpectedCommaInList {
849+
#[primary_span]
850+
pub span: Span,
851+
}
852+
853+
#[derive(Diagnostic)]
854+
#[diag(builtin_macros_only_one_argument)]
855+
pub(crate) struct OnlyOneArgument<'a> {
856+
#[primary_span]
857+
pub span: Span,
858+
pub name: &'a str,
859+
}
860+
861+
#[derive(Diagnostic)]
862+
#[diag(builtin_macros_takes_no_arguments)]
863+
pub(crate) struct TakesNoArguments<'a> {
864+
#[primary_span]
865+
pub span: Span,
866+
pub name: &'a str,
867+
}

compiler/rustc_builtin_macros/src/format.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::errors;
2+
use crate::util::expr_to_spanned_string;
13
use parse::Position::ArgumentNamed;
24
use rustc_ast::ptr::P;
35
use rustc_ast::tokenstream::TokenStream;
@@ -10,14 +12,13 @@ use rustc_ast::{
1012
use rustc_data_structures::fx::FxHashSet;
1113
use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
1214
use rustc_expand::base::*;
15+
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
16+
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
1317
use rustc_parse::parser::Recovered;
1418
use rustc_parse_format as parse;
1519
use rustc_span::symbol::{Ident, Symbol};
1620
use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
1721

18-
use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
19-
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
20-
2122
// The format_args!() macro is expanded in three steps:
2223
// 1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
2324
// but doesn't parse the template (the literal) itself.
@@ -38,8 +39,6 @@ enum PositionUsedAs {
3839
}
3940
use PositionUsedAs::*;
4041

41-
use crate::errors;
42-
4342
#[derive(Debug)]
4443
struct MacroInput {
4544
fmtstr: P<Expr>,

compiler/rustc_builtin_macros/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ mod pattern_type;
5050
mod source_util;
5151
mod test;
5252
mod trace_macros;
53-
mod util;
5453

5554
pub mod asm;
5655
pub mod cmdline_attrs;
5756
pub mod proc_macro_harness;
5857
pub mod standard_library_imports;
5958
pub mod test_harness;
59+
pub mod util;
6060

6161
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
6262

compiler/rustc_builtin_macros/src/source_util.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1+
use crate::util::{
2+
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
3+
};
14
use rustc_ast as ast;
25
use rustc_ast::ptr::P;
36
use rustc_ast::token;
47
use rustc_ast::tokenstream::TokenStream;
58
use rustc_ast_pretty::pprust;
69
use rustc_data_structures::sync::Lrc;
710
use rustc_expand::base::{
8-
check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
9-
resolve_path,
11+
resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
1012
};
11-
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt};
12-
use rustc_expand::base::{MacEager, MacResult, MacroExpanderResult};
1313
use rustc_expand::module::DirOwnership;
1414
use rustc_parse::new_parser_from_file;
1515
use rustc_parse::parser::{ForceCollect, Parser};

compiler/rustc_builtin_macros/src/util.rs

Lines changed: 184 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
use rustc_ast::{attr, AttrStyle, Attribute, MetaItem};
2-
use rustc_expand::base::{Annotatable, ExtCtxt};
1+
use crate::errors;
2+
use rustc_ast::tokenstream::TokenStream;
3+
use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem};
4+
use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
5+
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
6+
use rustc_expand::expand::AstFragment;
37
use rustc_feature::AttributeTemplate;
48
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
5-
use rustc_parse::validate_attr;
6-
use rustc_span::Symbol;
9+
use rustc_parse::{parser, validate_attr};
10+
use rustc_session::errors::report_lit_error;
11+
use rustc_span::{BytePos, Span, Symbol};
712

813
pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
914
// All the built-in macro attributes are "words" at the moment.
@@ -46,3 +51,178 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
4651
}
4752
}
4853
}
54+
55+
/// `Ok` represents successfully retrieving the string literal at the correct
56+
/// position, e.g., `println("abc")`.
57+
type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
58+
59+
/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
60+
/// but another type of expression is obtained instead.
61+
/// - `Err` is returned when the conversion process fails.
62+
type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>;
63+
64+
/// Extracts a string literal from the macro expanded version of `expr`,
65+
/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
66+
/// The returned bool indicates whether an applicable suggestion has already been
67+
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
68+
/// indicates that an ast error was encountered.
69+
// FIXME(Nilstrieb) Make this function setup translatable
70+
#[allow(rustc::untranslatable_diagnostic)]
71+
pub(crate) fn expr_to_spanned_string<'a>(
72+
cx: &'a mut ExtCtxt<'_>,
73+
expr: P<ast::Expr>,
74+
err_msg: &'static str,
75+
) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
76+
if !cx.force_mode
77+
&& let ast::ExprKind::MacCall(m) = &expr.kind
78+
&& cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
79+
{
80+
return ExpandResult::Retry(());
81+
}
82+
83+
// Perform eager expansion on the expression.
84+
// We want to be able to handle e.g., `concat!("foo", "bar")`.
85+
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
86+
87+
ExpandResult::Ready(Err(match expr.kind {
88+
ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
89+
Ok(ast::LitKind::Str(s, style)) => {
90+
return ExpandResult::Ready(Ok((s, style, expr.span)));
91+
}
92+
Ok(ast::LitKind::ByteStr(..)) => {
93+
let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
94+
let span = expr.span.shrink_to_lo();
95+
err.span_suggestion(
96+
span.with_hi(span.lo() + BytePos(1)),
97+
"consider removing the leading `b`",
98+
"",
99+
Applicability::MaybeIncorrect,
100+
);
101+
Ok((err, true))
102+
}
103+
Ok(ast::LitKind::Err(guar)) => Err(guar),
104+
Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)),
105+
_ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
106+
},
107+
ast::ExprKind::Err(guar) => Err(guar),
108+
ast::ExprKind::Dummy => {
109+
cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`")
110+
}
111+
_ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
112+
}))
113+
}
114+
115+
/// Extracts a string literal from the macro expanded version of `expr`,
116+
/// emitting `err_msg` if `expr` is not a string literal. This does not stop
117+
/// compilation on error, merely emits a non-fatal error and returns `Err`.
118+
pub(crate) fn expr_to_string(
119+
cx: &mut ExtCtxt<'_>,
120+
expr: P<ast::Expr>,
121+
err_msg: &'static str,
122+
) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
123+
expr_to_spanned_string(cx, expr, err_msg).map(|res| {
124+
res.map_err(|err| match err {
125+
Ok((err, _)) => err.emit(),
126+
Err(guar) => guar,
127+
})
128+
.map(|(symbol, style, _)| (symbol, style))
129+
})
130+
}
131+
132+
/// Non-fatally assert that `tts` is empty. Note that this function
133+
/// returns even when `tts` is non-empty, macros that *need* to stop
134+
/// compilation should call `cx.diagnostic().abort_if_errors()`
135+
/// (this should be done as rarely as possible).
136+
pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
137+
if !tts.is_empty() {
138+
cx.dcx().emit_err(errors::TakesNoArguments { span, name });
139+
}
140+
}
141+
142+
/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`.
143+
pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<P<ast::Expr>, ErrorGuaranteed> {
144+
let guar = match p.parse_expr() {
145+
Ok(expr) => return Ok(expr),
146+
Err(err) => err.emit(),
147+
};
148+
while p.token != token::Eof {
149+
p.bump();
150+
}
151+
Err(guar)
152+
}
153+
154+
/// Interpreting `tts` as a comma-separated sequence of expressions,
155+
/// expect exactly one string literal, or emit an error and return `Err`.
156+
pub(crate) fn get_single_str_from_tts(
157+
cx: &mut ExtCtxt<'_>,
158+
span: Span,
159+
tts: TokenStream,
160+
name: &str,
161+
) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> {
162+
get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s))
163+
}
164+
165+
pub(crate) fn get_single_str_spanned_from_tts(
166+
cx: &mut ExtCtxt<'_>,
167+
span: Span,
168+
tts: TokenStream,
169+
name: &str,
170+
) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> {
171+
let mut p = cx.new_parser_from_tts(tts);
172+
if p.token == token::Eof {
173+
let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
174+
return ExpandResult::Ready(Err(guar));
175+
}
176+
let ret = match parse_expr(&mut p) {
177+
Ok(ret) => ret,
178+
Err(guar) => return ExpandResult::Ready(Err(guar)),
179+
};
180+
let _ = p.eat(&token::Comma);
181+
182+
if p.token != token::Eof {
183+
cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
184+
}
185+
expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
186+
res.map_err(|err| match err {
187+
Ok((err, _)) => err.emit(),
188+
Err(guar) => guar,
189+
})
190+
.map(|(symbol, _style, span)| (symbol, span))
191+
})
192+
}
193+
194+
/// Extracts comma-separated expressions from `tts`.
195+
/// On error, emit it, and return `Err`.
196+
pub(crate) fn get_exprs_from_tts(
197+
cx: &mut ExtCtxt<'_>,
198+
tts: TokenStream,
199+
) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> {
200+
let mut p = cx.new_parser_from_tts(tts);
201+
let mut es = Vec::new();
202+
while p.token != token::Eof {
203+
let expr = match parse_expr(&mut p) {
204+
Ok(expr) => expr,
205+
Err(guar) => return ExpandResult::Ready(Err(guar)),
206+
};
207+
if !cx.force_mode
208+
&& let ast::ExprKind::MacCall(m) = &expr.kind
209+
&& cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
210+
{
211+
return ExpandResult::Retry(());
212+
}
213+
214+
// Perform eager expansion on the expression.
215+
// We want to be able to handle e.g., `concat!("foo", "bar")`.
216+
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
217+
218+
es.push(expr);
219+
if p.eat(&token::Comma) {
220+
continue;
221+
}
222+
if p.token != token::Eof {
223+
let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
224+
return ExpandResult::Ready(Err(guar));
225+
}
226+
}
227+
ExpandResult::Ready(Ok(es))
228+
}

0 commit comments

Comments
 (0)