Skip to content

Commit 8401398

Browse files
committed
Auto merge of #148762 - matthiaskrgr:rollup-4oifvkr, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #148248 (Constify `ControlFlow` methods without unstable bounds) - #148285 (Constify `ControlFlow` methods with unstable bounds) - #148510 (compiletest: Do the known-directives check only once, and improve its error message) - #148655 (Fix invalid macro tag generation for keywords which can be followed by values) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 6647be9 + 5430082 commit 8401398

File tree

8 files changed

+177
-98
lines changed

8 files changed

+177
-98
lines changed

library/core/src/ops/control_flow.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::marker::Destruct;
12
use crate::{convert, ops};
23

34
/// Used to tell an operation whether it should exit early or go on as usual.
@@ -150,7 +151,8 @@ impl<B, C> ControlFlow<B, C> {
150151
/// ```
151152
#[inline]
152153
#[stable(feature = "control_flow_enum_is", since = "1.59.0")]
153-
pub fn is_break(&self) -> bool {
154+
#[rustc_const_unstable(feature = "min_const_control_flow", issue = "148738")]
155+
pub const fn is_break(&self) -> bool {
154156
matches!(*self, ControlFlow::Break(_))
155157
}
156158

@@ -166,7 +168,8 @@ impl<B, C> ControlFlow<B, C> {
166168
/// ```
167169
#[inline]
168170
#[stable(feature = "control_flow_enum_is", since = "1.59.0")]
169-
pub fn is_continue(&self) -> bool {
171+
#[rustc_const_unstable(feature = "min_const_control_flow", issue = "148738")]
172+
pub const fn is_continue(&self) -> bool {
170173
matches!(*self, ControlFlow::Continue(_))
171174
}
172175

@@ -183,7 +186,11 @@ impl<B, C> ControlFlow<B, C> {
183186
/// ```
184187
#[inline]
185188
#[stable(feature = "control_flow_enum", since = "1.83.0")]
186-
pub fn break_value(self) -> Option<B> {
189+
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
190+
pub const fn break_value(self) -> Option<B>
191+
where
192+
Self: [const] Destruct,
193+
{
187194
match self {
188195
ControlFlow::Continue(..) => None,
189196
ControlFlow::Break(x) => Some(x),
@@ -257,7 +264,8 @@ impl<B, C> ControlFlow<B, C> {
257264
/// ```
258265
#[inline]
259266
#[unstable(feature = "control_flow_ok", issue = "140266")]
260-
pub fn break_ok(self) -> Result<B, C> {
267+
#[rustc_const_unstable(feature = "min_const_control_flow", issue = "148738")]
268+
pub const fn break_ok(self) -> Result<B, C> {
261269
match self {
262270
ControlFlow::Continue(c) => Err(c),
263271
ControlFlow::Break(b) => Ok(b),
@@ -268,7 +276,11 @@ impl<B, C> ControlFlow<B, C> {
268276
/// to the break value in case it exists.
269277
#[inline]
270278
#[stable(feature = "control_flow_enum", since = "1.83.0")]
271-
pub fn map_break<T>(self, f: impl FnOnce(B) -> T) -> ControlFlow<T, C> {
279+
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
280+
pub const fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
281+
where
282+
F: [const] FnOnce(B) -> T + [const] Destruct,
283+
{
272284
match self {
273285
ControlFlow::Continue(x) => ControlFlow::Continue(x),
274286
ControlFlow::Break(x) => ControlFlow::Break(f(x)),
@@ -288,7 +300,11 @@ impl<B, C> ControlFlow<B, C> {
288300
/// ```
289301
#[inline]
290302
#[stable(feature = "control_flow_enum", since = "1.83.0")]
291-
pub fn continue_value(self) -> Option<C> {
303+
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
304+
pub const fn continue_value(self) -> Option<C>
305+
where
306+
Self: [const] Destruct,
307+
{
292308
match self {
293309
ControlFlow::Continue(x) => Some(x),
294310
ControlFlow::Break(..) => None,
@@ -361,7 +377,8 @@ impl<B, C> ControlFlow<B, C> {
361377
/// ```
362378
#[inline]
363379
#[unstable(feature = "control_flow_ok", issue = "140266")]
364-
pub fn continue_ok(self) -> Result<C, B> {
380+
#[rustc_const_unstable(feature = "min_const_control_flow", issue = "148738")]
381+
pub const fn continue_ok(self) -> Result<C, B> {
365382
match self {
366383
ControlFlow::Continue(c) => Ok(c),
367384
ControlFlow::Break(b) => Err(b),
@@ -372,7 +389,11 @@ impl<B, C> ControlFlow<B, C> {
372389
/// to the continue value in case it exists.
373390
#[inline]
374391
#[stable(feature = "control_flow_enum", since = "1.83.0")]
375-
pub fn map_continue<T>(self, f: impl FnOnce(C) -> T) -> ControlFlow<B, T> {
392+
#[rustc_const_unstable(feature = "const_control_flow", issue = "148739")]
393+
pub const fn map_continue<T, F>(self, f: F) -> ControlFlow<B, T>
394+
where
395+
F: [const] FnOnce(C) -> T + [const] Destruct,
396+
{
376397
match self {
377398
ControlFlow::Continue(x) => ControlFlow::Continue(f(x)),
378399
ControlFlow::Break(x) => ControlFlow::Break(x),

src/librustdoc/html/highlight.rs

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,9 @@ impl<'a> Iterator for TokenIter<'a> {
789789
}
790790
}
791791

792+
/// Used to know if a keyword followed by a `!` should never be treated as a macro.
793+
const NON_MACRO_KEYWORDS: &[&str] = &["if", "while", "match", "break", "return", "impl"];
794+
792795
/// This iterator comes from the same idea than "Peekable" except that it allows to "peek" more than
793796
/// just the next item by using `peek_next`. The `peek` method always returns the next item after
794797
/// the current one whereas `peek_next` will return the next item after the last one peeked.
@@ -1010,6 +1013,19 @@ impl<'src> Classifier<'src> {
10101013
}
10111014
}
10121015

1016+
fn new_macro_span(
1017+
&mut self,
1018+
text: &'src str,
1019+
sink: &mut dyn FnMut(Span, Highlight<'src>),
1020+
before: u32,
1021+
file_span: Span,
1022+
) {
1023+
self.in_macro = true;
1024+
let span = new_span(before, text, file_span);
1025+
sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) });
1026+
sink(span, Highlight::Token { text, class: None });
1027+
}
1028+
10131029
/// Single step of highlighting. This will classify `token`, but maybe also a couple of
10141030
/// following ones as well.
10151031
///
@@ -1216,16 +1232,46 @@ impl<'src> Classifier<'src> {
12161232
LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
12171233
},
12181234
TokenKind::GuardedStrPrefix => return no_highlight(sink),
1219-
TokenKind::Ident | TokenKind::RawIdent
1220-
if let Some((TokenKind::Bang, _)) = self.peek_non_trivia() =>
1221-
{
1222-
self.in_macro = true;
1223-
let span = new_span(before, text, file_span);
1224-
sink(DUMMY_SP, Highlight::EnterSpan { class: Class::Macro(span) });
1225-
sink(span, Highlight::Token { text, class: None });
1235+
TokenKind::RawIdent if let Some((TokenKind::Bang, _)) = self.peek_non_trivia() => {
1236+
self.new_macro_span(text, sink, before, file_span);
12261237
return;
12271238
}
1228-
TokenKind::Ident => self.classify_ident(before, text),
1239+
// Macro non-terminals (meta vars) take precedence.
1240+
TokenKind::Ident if self.in_macro_nonterminal => {
1241+
self.in_macro_nonterminal = false;
1242+
Class::MacroNonTerminal
1243+
}
1244+
TokenKind::Ident => {
1245+
let file_span = self.file_span;
1246+
let span = || new_span(before, text, file_span);
1247+
1248+
match text {
1249+
"ref" | "mut" => Class::RefKeyWord,
1250+
"false" | "true" => Class::Bool,
1251+
"self" | "Self" => Class::Self_(span()),
1252+
"Option" | "Result" => Class::PreludeTy(span()),
1253+
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal(span()),
1254+
_ if self.is_weak_keyword(text) || is_keyword(Symbol::intern(text)) => {
1255+
// So if it's not a keyword which can be followed by a value (like `if` or
1256+
// `return`) and the next non-whitespace token is a `!`, then we consider
1257+
// it's a macro.
1258+
if !NON_MACRO_KEYWORDS.contains(&text)
1259+
&& matches!(self.peek_non_trivia(), Some((TokenKind::Bang, _)))
1260+
{
1261+
self.new_macro_span(text, sink, before, file_span);
1262+
return;
1263+
}
1264+
Class::KeyWord
1265+
}
1266+
// If it's not a keyword and the next non whitespace token is a `!`, then
1267+
// we consider it's a macro.
1268+
_ if matches!(self.peek_non_trivia(), Some((TokenKind::Bang, _))) => {
1269+
self.new_macro_span(text, sink, before, file_span);
1270+
return;
1271+
}
1272+
_ => Class::Ident(span()),
1273+
}
1274+
}
12291275
TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => {
12301276
Class::Ident(new_span(before, text, file_span))
12311277
}
@@ -1246,27 +1292,6 @@ impl<'src> Classifier<'src> {
12461292
}
12471293
}
12481294

1249-
fn classify_ident(&mut self, before: u32, text: &'src str) -> Class {
1250-
// Macro non-terminals (meta vars) take precedence.
1251-
if self.in_macro_nonterminal {
1252-
self.in_macro_nonterminal = false;
1253-
return Class::MacroNonTerminal;
1254-
}
1255-
1256-
let file_span = self.file_span;
1257-
let span = || new_span(before, text, file_span);
1258-
1259-
match text {
1260-
"ref" | "mut" => Class::RefKeyWord,
1261-
"false" | "true" => Class::Bool,
1262-
"self" | "Self" => Class::Self_(span()),
1263-
"Option" | "Result" => Class::PreludeTy(span()),
1264-
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal(span()),
1265-
_ if self.is_weak_keyword(text) || is_keyword(Symbol::intern(text)) => Class::KeyWord,
1266-
_ => Class::Ident(span()),
1267-
}
1268-
}
1269-
12701295
fn is_weak_keyword(&mut self, text: &str) -> bool {
12711296
// NOTE: `yeet` (`do yeet $expr`), `catch` (`do catch $block`), `default` (specialization),
12721297
// `contract_{ensures,requires}`, `builtin` (builtin_syntax) & `reuse` (fn_delegation) are

src/tools/compiletest/src/directives.rs

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::debuggers::{extract_cdb_version, extract_gdb_version};
1111
pub(crate) use crate::directives::auxiliary::AuxProps;
1212
use crate::directives::auxiliary::parse_and_update_aux;
1313
use crate::directives::directive_names::{
14-
KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
14+
KNOWN_DIRECTIVE_NAMES_SET, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
1515
};
1616
pub(crate) use crate::directives::file::FileDirectives;
1717
use crate::directives::line::{DirectiveLine, line_directive};
@@ -53,25 +53,17 @@ impl EarlyProps {
5353
config: &Config,
5454
file_directives: &FileDirectives<'_>,
5555
) -> Self {
56-
let testfile = file_directives.path;
5756
let mut props = EarlyProps::default();
58-
let mut poisoned = false;
5957

6058
iter_directives(
6159
config.mode,
62-
&mut poisoned,
6360
file_directives,
6461
// (dummy comment to force args into vertical layout)
6562
&mut |ln: &DirectiveLine<'_>| {
6663
config.parse_and_update_revisions(ln, &mut props.revisions);
6764
},
6865
);
6966

70-
if poisoned {
71-
eprintln!("errors encountered during EarlyProps parsing: {}", testfile);
72-
panic!("errors encountered during EarlyProps parsing");
73-
}
74-
7567
props
7668
}
7769
}
@@ -358,12 +350,10 @@ impl TestProps {
358350
let file_contents = fs::read_to_string(testfile).unwrap();
359351
let file_directives = FileDirectives::from_file_contents(testfile, &file_contents);
360352

361-
let mut poisoned = false;
362-
363353
iter_directives(
364354
config.mode,
365-
&mut poisoned,
366355
&file_directives,
356+
// (dummy comment to force args into vertical layout)
367357
&mut |ln: &DirectiveLine<'_>| {
368358
if !ln.applies_to_test_revision(test_revision) {
369359
return;
@@ -634,11 +624,6 @@ impl TestProps {
634624
);
635625
},
636626
);
637-
638-
if poisoned {
639-
eprintln!("errors encountered during TestProps parsing: {}", testfile);
640-
panic!("errors encountered during TestProps parsing");
641-
}
642627
}
643628

644629
if self.should_ice {
@@ -775,6 +760,34 @@ impl TestProps {
775760
}
776761
}
777762

763+
pub(crate) fn do_early_directives_check(
764+
mode: TestMode,
765+
file_directives: &FileDirectives<'_>,
766+
) -> Result<(), String> {
767+
let testfile = file_directives.path;
768+
769+
for directive_line @ DirectiveLine { line_number, .. } in &file_directives.lines {
770+
let CheckDirectiveResult { is_known_directive, trailing_directive } =
771+
check_directive(directive_line, mode);
772+
773+
if !is_known_directive {
774+
return Err(format!(
775+
"ERROR: unknown compiletest directive `{directive}` at {testfile}:{line_number}",
776+
directive = directive_line.display(),
777+
));
778+
}
779+
780+
if let Some(trailing_directive) = &trailing_directive {
781+
return Err(format!(
782+
"ERROR: detected trailing compiletest directive `{trailing_directive}` at {testfile}:{line_number}\n\
783+
HELP: put the directive on its own line: `//@ {trailing_directive}`"
784+
));
785+
}
786+
}
787+
788+
Ok(())
789+
}
790+
778791
pub(crate) struct CheckDirectiveResult<'ln> {
779792
is_known_directive: bool,
780793
trailing_directive: Option<&'ln str>,
@@ -786,7 +799,7 @@ fn check_directive<'a>(
786799
) -> CheckDirectiveResult<'a> {
787800
let &DirectiveLine { name: directive_name, .. } = directive_ln;
788801

789-
let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
802+
let is_known_directive = KNOWN_DIRECTIVE_NAMES_SET.contains(&directive_name)
790803
|| match mode {
791804
TestMode::Rustdoc => KNOWN_HTMLDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
792805
TestMode::RustdocJson => KNOWN_JSONDOCCK_DIRECTIVE_NAMES.contains(&directive_name),
@@ -799,7 +812,7 @@ fn check_directive<'a>(
799812
let trailing_directive = directive_ln
800813
.remark_after_space()
801814
.map(|remark| remark.trim_start().split(' ').next().unwrap())
802-
.filter(|token| KNOWN_DIRECTIVE_NAMES.contains(token));
815+
.filter(|token| KNOWN_DIRECTIVE_NAMES_SET.contains(token));
803816

804817
// FIXME(Zalathar): Consider emitting specialized error/help messages for
805818
// bogus directive names that are similar to real ones, e.g.:
@@ -811,7 +824,6 @@ fn check_directive<'a>(
811824

812825
fn iter_directives(
813826
mode: TestMode,
814-
poisoned: &mut bool,
815827
file_directives: &FileDirectives<'_>,
816828
it: &mut dyn FnMut(&DirectiveLine<'_>),
817829
) {
@@ -837,36 +849,7 @@ fn iter_directives(
837849
}
838850
}
839851

840-
for directive_line @ &DirectiveLine { line_number, .. } in &file_directives.lines {
841-
// Perform unknown directive check on Rust files.
842-
if testfile.extension() == Some("rs") {
843-
let CheckDirectiveResult { is_known_directive, trailing_directive } =
844-
check_directive(directive_line, mode);
845-
846-
if !is_known_directive {
847-
*poisoned = true;
848-
849-
error!(
850-
"{testfile}:{line_number}: detected unknown compiletest test directive `{}`",
851-
directive_line.display(),
852-
);
853-
854-
return;
855-
}
856-
857-
if let Some(trailing_directive) = &trailing_directive {
858-
*poisoned = true;
859-
860-
error!(
861-
"{testfile}:{line_number}: detected trailing compiletest test directive `{}`",
862-
trailing_directive,
863-
);
864-
help!("put the trailing directive in its own line: `//@ {}`", trailing_directive);
865-
866-
return;
867-
}
868-
}
869-
852+
for directive_line in &file_directives.lines {
870853
it(directive_line);
871854
}
872855
}
@@ -1304,12 +1287,9 @@ pub(crate) fn make_test_description(
13041287
let mut ignore_message = None;
13051288
let mut should_fail = false;
13061289

1307-
let mut local_poisoned = false;
1308-
13091290
// Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
13101291
iter_directives(
13111292
config.mode,
1312-
&mut local_poisoned,
13131293
file_directives,
13141294
&mut |ln @ &DirectiveLine { line_number, .. }| {
13151295
if !ln.applies_to_test_revision(test_revision) {
@@ -1358,11 +1338,6 @@ pub(crate) fn make_test_description(
13581338
},
13591339
);
13601340

1361-
if local_poisoned {
1362-
eprintln!("errors encountered when trying to make test description: {}", path);
1363-
panic!("errors encountered when trying to make test description");
1364-
}
1365-
13661341
// The `should-fail` annotation doesn't apply to pretty tests,
13671342
// since we run the pretty printer across all tests by default.
13681343
// If desired, we could add a `should-fail-pretty` annotation.

0 commit comments

Comments
 (0)