Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 14b1552

Browse files
committedApr 23, 2020
Auto merge of rust-lang#71483 - Dylan-DPC:rollup-c2h9s8b, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - rust-lang#70633 (Confusing suggestion on incorrect closing `}`) - rust-lang#71404 (Don't fuse Chain in its second iterator) - rust-lang#71408 (Check code blocks tags) - rust-lang#71442 (Add a "by reference" adaptor for `AllocRef`) - rust-lang#71446 (Only use read_unaligned in transmute_copy if necessary) - rust-lang#71470 (Fix doc links) - rust-lang#71479 (add back Scalar::null_ptr) Failed merges: r? @ghost
2 parents 413a129 + b107eb5 commit 14b1552

30 files changed

+939
-73
lines changed
 

‎src/liballoc/collections/vec_deque.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ pub struct VecDeque<T> {
7373
/// It produces the following sequence of matching slices:
7474
///
7575
/// ([0 1], [a b])
76-
/// ([2], [c])
76+
/// (\[2\], \[c\])
7777
/// ([3 4], [d e])
7878
///
7979
/// and the uneven remainder of either A or B is skipped.

‎src/liballoc/rc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1024,7 +1024,7 @@ unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
10241024
}
10251025

10261026
impl<T> Rc<[T]> {
1027-
/// Copy elements from slice into newly allocated Rc<[T]>
1027+
/// Copy elements from slice into newly allocated Rc<\[T\]>
10281028
///
10291029
/// Unsafe because the caller must either take ownership or bind `T: Copy`
10301030
unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> {

‎src/liballoc/sync.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ unsafe fn set_data_ptr<T: ?Sized, U>(mut ptr: *mut T, data: *mut U) -> *mut T {
902902
}
903903

904904
impl<T> Arc<[T]> {
905-
/// Copy elements from slice into newly allocated Arc<[T]>
905+
/// Copy elements from slice into newly allocated Arc<\[T\]>
906906
///
907907
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
908908
unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> {

‎src/libcore/alloc/mod.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,4 +364,51 @@ pub unsafe trait AllocRef {
364364
}
365365
}
366366
}
367+
368+
/// Creates a "by reference" adaptor for this instance of `AllocRef`.
369+
///
370+
/// The returned adaptor also implements `AllocRef` and will simply borrow this.
371+
#[inline(always)]
372+
fn by_ref(&mut self) -> &mut Self {
373+
self
374+
}
375+
}
376+
377+
#[unstable(feature = "allocator_api", issue = "32838")]
378+
unsafe impl<A> AllocRef for &mut A
379+
where
380+
A: AllocRef + ?Sized,
381+
{
382+
#[inline]
383+
fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
384+
(**self).alloc(layout, init)
385+
}
386+
387+
#[inline]
388+
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
389+
(**self).dealloc(ptr, layout)
390+
}
391+
392+
#[inline]
393+
unsafe fn grow(
394+
&mut self,
395+
ptr: NonNull<u8>,
396+
layout: Layout,
397+
new_size: usize,
398+
placement: ReallocPlacement,
399+
init: AllocInit,
400+
) -> Result<MemoryBlock, AllocErr> {
401+
(**self).grow(ptr, layout, new_size, placement, init)
402+
}
403+
404+
#[inline]
405+
unsafe fn shrink(
406+
&mut self,
407+
ptr: NonNull<u8>,
408+
layout: Layout,
409+
new_size: usize,
410+
placement: ReallocPlacement,
411+
) -> Result<MemoryBlock, AllocErr> {
412+
(**self).shrink(ptr, layout, new_size, placement)
413+
}
367414
}

‎src/libcore/ffi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
282282
mod sealed_trait {
283283
/// Trait which whitelists the allowed types to be used with [VaList::arg]
284284
///
285-
/// [VaList::va_arg]: struct.VaList.html#method.arg
285+
/// [VaList::arg]: ../struct.VaList.html#method.arg
286286
#[unstable(
287287
feature = "c_variadic",
288288
reason = "the `c_variadic` feature has not been properly tested on \

‎src/libcore/iter/adapters/chain.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub struct Chain<A, B> {
1818
// adapter because its specialization for `FusedIterator` unconditionally descends into the
1919
// iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
2020
// hurts compiler performance to add more iterator layers to `Chain`.
21+
//
22+
// Only the "first" iterator is actually set `None` when exhausted, depending on whether you
23+
// iterate forward or backward. If you mix directions, then both sides may be `None`.
2124
a: Option<A>,
2225
b: Option<B>,
2326
}
@@ -43,6 +46,17 @@ macro_rules! fuse {
4346
};
4447
}
4548

49+
/// Try an iterator method without fusing,
50+
/// like an inline `.as_mut().and_then(...)`
51+
macro_rules! maybe {
52+
($self:ident . $iter:ident . $($call:tt)+) => {
53+
match $self.$iter {
54+
Some(ref mut iter) => iter.$($call)+,
55+
None => None,
56+
}
57+
};
58+
}
59+
4660
#[stable(feature = "rust1", since = "1.0.0")]
4761
impl<A, B> Iterator for Chain<A, B>
4862
where
@@ -54,7 +68,7 @@ where
5468
#[inline]
5569
fn next(&mut self) -> Option<A::Item> {
5670
match fuse!(self.a.next()) {
57-
None => fuse!(self.b.next()),
71+
None => maybe!(self.b.next()),
5872
item => item,
5973
}
6074
}
@@ -85,7 +99,7 @@ where
8599
}
86100
if let Some(ref mut b) = self.b {
87101
acc = b.try_fold(acc, f)?;
88-
self.b = None;
102+
// we don't fuse the second iterator
89103
}
90104
Try::from_ok(acc)
91105
}
@@ -114,7 +128,7 @@ where
114128
}
115129
self.a = None;
116130
}
117-
fuse!(self.b.nth(n))
131+
maybe!(self.b.nth(n))
118132
}
119133

120134
#[inline]
@@ -123,7 +137,7 @@ where
123137
P: FnMut(&Self::Item) -> bool,
124138
{
125139
match fuse!(self.a.find(&mut predicate)) {
126-
None => fuse!(self.b.find(predicate)),
140+
None => maybe!(self.b.find(predicate)),
127141
item => item,
128142
}
129143
}
@@ -174,7 +188,7 @@ where
174188
#[inline]
175189
fn next_back(&mut self) -> Option<A::Item> {
176190
match fuse!(self.b.next_back()) {
177-
None => fuse!(self.a.next_back()),
191+
None => maybe!(self.a.next_back()),
178192
item => item,
179193
}
180194
}
@@ -190,7 +204,7 @@ where
190204
}
191205
self.b = None;
192206
}
193-
fuse!(self.a.nth_back(n))
207+
maybe!(self.a.nth_back(n))
194208
}
195209

196210
#[inline]
@@ -199,7 +213,7 @@ where
199213
P: FnMut(&Self::Item) -> bool,
200214
{
201215
match fuse!(self.b.rfind(&mut predicate)) {
202-
None => fuse!(self.a.rfind(predicate)),
216+
None => maybe!(self.a.rfind(predicate)),
203217
item => item,
204218
}
205219
}
@@ -216,7 +230,7 @@ where
216230
}
217231
if let Some(ref mut a) = self.a {
218232
acc = a.try_rfold(acc, f)?;
219-
self.a = None;
233+
// we don't fuse the second iterator
220234
}
221235
Try::from_ok(acc)
222236
}
@@ -236,8 +250,6 @@ where
236250
}
237251

238252
// Note: *both* must be fused to handle double-ended iterators.
239-
// Now that we "fuse" both sides, we *could* implement this unconditionally,
240-
// but we should be cautious about committing to that in the public API.
241253
#[stable(feature = "fused", since = "1.26.0")]
242254
impl<A, B> FusedIterator for Chain<A, B>
243255
where

‎src/libcore/mem/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,12 @@ pub fn drop<T>(_x: T) {}
924924
#[inline]
925925
#[stable(feature = "rust1", since = "1.0.0")]
926926
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
927-
ptr::read_unaligned(src as *const T as *const U)
927+
// If U has a higher alignment requirement, src may not be suitably aligned.
928+
if align_of::<U>() > align_of::<T>() {
929+
ptr::read_unaligned(src as *const T as *const U)
930+
} else {
931+
ptr::read(src as *const T as *const U)
932+
}
928933
}
929934

930935
/// Opaque type representing the discriminant of an enum.

‎src/libcore/tests/iter.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -207,50 +207,64 @@ fn test_iterator_chain_find() {
207207
assert_eq!(iter.next(), None);
208208
}
209209

210-
#[test]
211-
fn test_iterator_chain_size_hint() {
212-
struct Iter {
213-
is_empty: bool,
214-
}
210+
struct Toggle {
211+
is_empty: bool,
212+
}
215213

216-
impl Iterator for Iter {
217-
type Item = ();
214+
impl Iterator for Toggle {
215+
type Item = ();
218216

219-
// alternates between `None` and `Some(())`
220-
fn next(&mut self) -> Option<Self::Item> {
221-
if self.is_empty {
222-
self.is_empty = false;
223-
None
224-
} else {
225-
self.is_empty = true;
226-
Some(())
227-
}
217+
// alternates between `None` and `Some(())`
218+
fn next(&mut self) -> Option<Self::Item> {
219+
if self.is_empty {
220+
self.is_empty = false;
221+
None
222+
} else {
223+
self.is_empty = true;
224+
Some(())
228225
}
226+
}
229227

230-
fn size_hint(&self) -> (usize, Option<usize>) {
231-
if self.is_empty { (0, Some(0)) } else { (1, Some(1)) }
232-
}
228+
fn size_hint(&self) -> (usize, Option<usize>) {
229+
if self.is_empty { (0, Some(0)) } else { (1, Some(1)) }
233230
}
231+
}
234232

235-
impl DoubleEndedIterator for Iter {
236-
fn next_back(&mut self) -> Option<Self::Item> {
237-
self.next()
238-
}
233+
impl DoubleEndedIterator for Toggle {
234+
fn next_back(&mut self) -> Option<Self::Item> {
235+
self.next()
239236
}
237+
}
240238

239+
#[test]
240+
fn test_iterator_chain_size_hint() {
241241
// this chains an iterator of length 0 with an iterator of length 1,
242242
// so after calling `.next()` once, the iterator is empty and the
243243
// state is `ChainState::Back`. `.size_hint()` should now disregard
244244
// the size hint of the left iterator
245-
let mut iter = Iter { is_empty: true }.chain(once(()));
245+
let mut iter = Toggle { is_empty: true }.chain(once(()));
246246
assert_eq!(iter.next(), Some(()));
247247
assert_eq!(iter.size_hint(), (0, Some(0)));
248248

249-
let mut iter = once(()).chain(Iter { is_empty: true });
249+
let mut iter = once(()).chain(Toggle { is_empty: true });
250250
assert_eq!(iter.next_back(), Some(()));
251251
assert_eq!(iter.size_hint(), (0, Some(0)));
252252
}
253253

254+
#[test]
255+
fn test_iterator_chain_unfused() {
256+
// Chain shouldn't be fused in its second iterator, depending on direction
257+
let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true });
258+
iter.next().unwrap_none();
259+
iter.next().unwrap();
260+
iter.next().unwrap_none();
261+
262+
let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty()));
263+
iter.next_back().unwrap_none();
264+
iter.next_back().unwrap();
265+
iter.next_back().unwrap_none();
266+
}
267+
254268
#[test]
255269
fn test_zip_nth() {
256270
let xs = [0, 1, 2, 4, 5];

‎src/libcore/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#![feature(unwrap_infallible)]
4343
#![feature(leading_trailing_ones)]
4444
#![feature(const_forget)]
45+
#![feature(option_unwrap_none)]
4546

4647
extern crate test;
4748

‎src/librustc_lint/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ use rustc_middle::ty::query::Providers;
6161
use rustc_middle::ty::TyCtxt;
6262
use rustc_session::lint::builtin::{
6363
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
64-
INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
64+
INTRA_DOC_LINK_RESOLUTION_FAILURE, INVALID_CODEBLOCK_ATTRIBUTE, MISSING_DOC_CODE_EXAMPLES,
65+
PRIVATE_DOC_TESTS,
6566
};
6667
use rustc_span::Span;
6768

@@ -299,6 +300,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
299300
add_lint_group!(
300301
"rustdoc",
301302
INTRA_DOC_LINK_RESOLUTION_FAILURE,
303+
INVALID_CODEBLOCK_ATTRIBUTE,
302304
MISSING_DOC_CODE_EXAMPLES,
303305
PRIVATE_DOC_TESTS
304306
);

‎src/librustc_middle/mir/interpret/value.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ impl<'tcx, Tag> Scalar<Tag> {
188188
}
189189
}
190190

191+
#[inline]
192+
pub fn null_ptr(cx: &impl HasDataLayout) -> Self {
193+
Scalar::Raw { data: 0, size: cx.data_layout().pointer_size.bytes() as u8 }
194+
}
195+
191196
#[inline]
192197
pub fn zst() -> Self {
193198
Scalar::Raw { data: 0, size: 0 }

‎src/librustc_parse/lexer/tokentrees.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{StringReader, UnmatchedBrace};
22

3-
use rustc_ast::token::{self, Token};
3+
use rustc_ast::token::{self, DelimToken, Token};
44
use rustc_ast::tokenstream::{
55
DelimSpan,
66
IsJoint::{self, *},
@@ -22,6 +22,7 @@ impl<'a> StringReader<'a> {
2222
matching_delim_spans: Vec::new(),
2323
last_unclosed_found_span: None,
2424
last_delim_empty_block_spans: FxHashMap::default(),
25+
matching_block_spans: Vec::new(),
2526
};
2627
let res = tt_reader.parse_all_token_trees();
2728
(res, tt_reader.unmatched_braces)
@@ -42,6 +43,9 @@ struct TokenTreesReader<'a> {
4243
last_unclosed_found_span: Option<Span>,
4344
/// Collect empty block spans that might have been auto-inserted by editors.
4445
last_delim_empty_block_spans: FxHashMap<token::DelimToken, Span>,
46+
/// Collect the spans of braces (Open, Close). Used only
47+
/// for detecting if blocks are empty and only braces.
48+
matching_block_spans: Vec<(Span, Span)>,
4549
}
4650

4751
impl<'a> TokenTreesReader<'a> {
@@ -77,6 +81,7 @@ impl<'a> TokenTreesReader<'a> {
7781

7882
fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
7983
let sm = self.string_reader.sess.source_map();
84+
8085
match self.token.kind {
8186
token::Eof => {
8287
let msg = "this file contains an unclosed delimiter";
@@ -146,6 +151,14 @@ impl<'a> TokenTreesReader<'a> {
146151
}
147152
}
148153

154+
match (open_brace, delim) {
155+
//only add braces
156+
(DelimToken::Brace, DelimToken::Brace) => {
157+
self.matching_block_spans.push((open_brace_span, close_brace_span));
158+
}
159+
_ => {}
160+
}
161+
149162
if self.open_braces.is_empty() {
150163
// Clear up these spans to avoid suggesting them as we've found
151164
// properly matched delimiters so far for an entire block.
@@ -164,6 +177,7 @@ impl<'a> TokenTreesReader<'a> {
164177
token::CloseDelim(other) => {
165178
let mut unclosed_delimiter = None;
166179
let mut candidate = None;
180+
167181
if self.last_unclosed_found_span != Some(self.token.span) {
168182
// do not complain about the same unclosed delimiter multiple times
169183
self.last_unclosed_found_span = Some(self.token.span);
@@ -224,12 +238,27 @@ impl<'a> TokenTreesReader<'a> {
224238
let mut err =
225239
self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
226240

227-
if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
228-
err.span_label(
229-
span,
230-
"this block is empty, you might have not meant to close it",
231-
);
241+
// Braces are added at the end, so the last element is the biggest block
242+
if let Some(parent) = self.matching_block_spans.last() {
243+
if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) {
244+
// Check if the (empty block) is in the last properly closed block
245+
if (parent.0.to(parent.1)).contains(span) {
246+
err.span_label(
247+
span,
248+
"block is empty, you might have not meant to close it",
249+
);
250+
} else {
251+
err.span_label(parent.0, "this opening brace...");
252+
253+
err.span_label(parent.1, "...matches this closing brace");
254+
}
255+
} else {
256+
err.span_label(parent.0, "this opening brace...");
257+
258+
err.span_label(parent.1, "...matches this closing brace");
259+
}
232260
}
261+
233262
err.span_label(self.token.span, "unexpected closing delimiter");
234263
Err(err)
235264
}

‎src/librustc_session/lint/builtin.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,12 @@ declare_lint! {
386386
"failures in resolving intra-doc link targets"
387387
}
388388

389+
declare_lint! {
390+
pub INVALID_CODEBLOCK_ATTRIBUTE,
391+
Warn,
392+
"codeblock attribute looks a lot like a known one"
393+
}
394+
389395
declare_lint! {
390396
pub MISSING_CRATE_LEVEL_DOCS,
391397
Allow,
@@ -553,6 +559,7 @@ declare_lint_pass! {
553559
UNSTABLE_NAME_COLLISIONS,
554560
IRREFUTABLE_LET_PATTERNS,
555561
INTRA_DOC_LINK_RESOLUTION_FAILURE,
562+
INVALID_CODEBLOCK_ATTRIBUTE,
556563
MISSING_CRATE_LEVEL_DOCS,
557564
MISSING_DOC_CODE_EXAMPLES,
558565
PRIVATE_DOC_TESTS,

‎src/librustdoc/core.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
253253
let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
254254
let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
255255
let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name;
256+
let invalid_codeblock_attribute_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTE.name;
256257

257258
// In addition to those specific lints, we also need to whitelist those given through
258259
// command line, otherwise they'll get ignored and we don't want that.
@@ -263,6 +264,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
263264
missing_doc_example.to_owned(),
264265
private_doc_tests.to_owned(),
265266
no_crate_level_docs.to_owned(),
267+
invalid_codeblock_attribute_name.to_owned(),
266268
];
267269

268270
whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
@@ -275,7 +277,10 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
275277

276278
let lint_opts = lints()
277279
.filter_map(|lint| {
278-
if lint.name == warnings_lint_name || lint.name == intra_link_resolution_failure_name {
280+
if lint.name == warnings_lint_name
281+
|| lint.name == intra_link_resolution_failure_name
282+
|| lint.name == invalid_codeblock_attribute_name
283+
{
279284
None
280285
} else {
281286
Some((lint.name_lower(), lint::Allow))

‎src/librustdoc/html/markdown.rs

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020
#![allow(non_camel_case_types)]
2121

2222
use rustc_data_structures::fx::FxHashMap;
23+
use rustc_hir::def_id::DefId;
24+
use rustc_hir::HirId;
25+
use rustc_middle::ty::TyCtxt;
26+
use rustc_session::lint;
2327
use rustc_span::edition::Edition;
28+
use rustc_span::Span;
2429
use std::borrow::Cow;
2530
use std::cell::RefCell;
2631
use std::collections::VecDeque;
@@ -192,7 +197,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
192197
if let Some(Event::Start(Tag::CodeBlock(kind))) = event {
193198
let parse_result = match kind {
194199
CodeBlockKind::Fenced(ref lang) => {
195-
LangString::parse(&lang, self.check_error_codes, false)
200+
LangString::parse_without_check(&lang, self.check_error_codes, false)
196201
}
197202
CodeBlockKind::Indented => LangString::all_false(),
198203
};
@@ -560,6 +565,7 @@ pub fn find_testable_code<T: test::Tester>(
560565
tests: &mut T,
561566
error_codes: ErrorCodes,
562567
enable_per_target_ignores: bool,
568+
extra_info: Option<&ExtraInfo<'_, '_>>,
563569
) {
564570
let mut parser = Parser::new(doc).into_offset_iter();
565571
let mut prev_offset = 0;
@@ -573,7 +579,12 @@ pub fn find_testable_code<T: test::Tester>(
573579
if lang.is_empty() {
574580
LangString::all_false()
575581
} else {
576-
LangString::parse(lang, error_codes, enable_per_target_ignores)
582+
LangString::parse(
583+
lang,
584+
error_codes,
585+
enable_per_target_ignores,
586+
extra_info,
587+
)
577588
}
578589
}
579590
CodeBlockKind::Indented => LangString::all_false(),
@@ -615,6 +626,49 @@ pub fn find_testable_code<T: test::Tester>(
615626
}
616627
}
617628

629+
pub struct ExtraInfo<'a, 'b> {
630+
hir_id: Option<HirId>,
631+
item_did: Option<DefId>,
632+
sp: Span,
633+
tcx: &'a TyCtxt<'b>,
634+
}
635+
636+
impl<'a, 'b> ExtraInfo<'a, 'b> {
637+
pub fn new(tcx: &'a TyCtxt<'b>, hir_id: HirId, sp: Span) -> ExtraInfo<'a, 'b> {
638+
ExtraInfo { hir_id: Some(hir_id), item_did: None, sp, tcx }
639+
}
640+
641+
pub fn new_did(tcx: &'a TyCtxt<'b>, did: DefId, sp: Span) -> ExtraInfo<'a, 'b> {
642+
ExtraInfo { hir_id: None, item_did: Some(did), sp, tcx }
643+
}
644+
645+
fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) {
646+
let hir_id = match (self.hir_id, self.item_did) {
647+
(Some(h), _) => h,
648+
(None, Some(item_did)) => {
649+
match self.tcx.hir().as_local_hir_id(item_did) {
650+
Some(hir_id) => hir_id,
651+
None => {
652+
// If non-local, no need to check anything.
653+
return;
654+
}
655+
}
656+
}
657+
(None, None) => return,
658+
};
659+
self.tcx.struct_span_lint_hir(
660+
lint::builtin::INVALID_CODEBLOCK_ATTRIBUTE,
661+
hir_id,
662+
self.sp,
663+
|lint| {
664+
let mut diag = lint.build(msg);
665+
diag.help(help);
666+
diag.emit();
667+
},
668+
);
669+
}
670+
}
671+
618672
#[derive(Eq, PartialEq, Clone, Debug)]
619673
pub struct LangString {
620674
original: String,
@@ -652,10 +706,19 @@ impl LangString {
652706
}
653707
}
654708

709+
fn parse_without_check(
710+
string: &str,
711+
allow_error_code_check: ErrorCodes,
712+
enable_per_target_ignores: bool,
713+
) -> LangString {
714+
Self::parse(string, allow_error_code_check, enable_per_target_ignores, None)
715+
}
716+
655717
fn parse(
656718
string: &str,
657719
allow_error_code_check: ErrorCodes,
658720
enable_per_target_ignores: bool,
721+
extra: Option<&ExtraInfo<'_, '_>>,
659722
) -> LangString {
660723
let allow_error_code_check = allow_error_code_check.as_bool();
661724
let mut seen_rust_tags = false;
@@ -715,6 +778,53 @@ impl LangString {
715778
seen_other_tags = true;
716779
}
717780
}
781+
x if extra.is_some() => {
782+
let s = x.to_lowercase();
783+
match if s == "compile-fail" || s == "compile_fail" || s == "compilefail" {
784+
Some((
785+
"compile_fail",
786+
"the code block will either not be tested if not marked as a rust one \
787+
or won't fail if it compiles successfully",
788+
))
789+
} else if s == "should-panic" || s == "should_panic" || s == "shouldpanic" {
790+
Some((
791+
"should_panic",
792+
"the code block will either not be tested if not marked as a rust one \
793+
or won't fail if it doesn't panic when running",
794+
))
795+
} else if s == "no-run" || s == "no_run" || s == "norun" {
796+
Some((
797+
"no_run",
798+
"the code block will either not be tested if not marked as a rust one \
799+
or will be run (which you might not want)",
800+
))
801+
} else if s == "allow-fail" || s == "allow_fail" || s == "allowfail" {
802+
Some((
803+
"allow_fail",
804+
"the code block will either not be tested if not marked as a rust one \
805+
or will be run (which you might not want)",
806+
))
807+
} else if s == "test-harness" || s == "test_harness" || s == "testharness" {
808+
Some((
809+
"test_harness",
810+
"the code block will either not be tested if not marked as a rust one \
811+
or the code will be wrapped inside a main function",
812+
))
813+
} else {
814+
None
815+
} {
816+
Some((flag, help)) => {
817+
if let Some(ref extra) = extra {
818+
extra.error_invalid_codeblock_attr(
819+
&format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
820+
help,
821+
);
822+
}
823+
}
824+
None => {}
825+
}
826+
seen_other_tags = true;
827+
}
718828
_ => seen_other_tags = true,
719829
}
720830
}
@@ -934,7 +1044,7 @@ crate struct RustCodeBlock {
9341044

9351045
/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
9361046
/// untagged (and assumed to be rust).
937-
crate fn rust_code_blocks(md: &str) -> Vec<RustCodeBlock> {
1047+
crate fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_, '_>) -> Vec<RustCodeBlock> {
9381048
let mut code_blocks = vec![];
9391049

9401050
if md.is_empty() {
@@ -951,7 +1061,7 @@ crate fn rust_code_blocks(md: &str) -> Vec<RustCodeBlock> {
9511061
let lang_string = if syntax.is_empty() {
9521062
LangString::all_false()
9531063
} else {
954-
LangString::parse(&*syntax, ErrorCodes::Yes, false)
1064+
LangString::parse(&*syntax, ErrorCodes::Yes, false, Some(extra_info))
9551065
};
9561066
if !lang_string.rust {
9571067
continue;

‎src/librustdoc/html/markdown/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fn test_lang_string_parse() {
6464
edition: Option<Edition>,
6565
) {
6666
assert_eq!(
67-
LangString::parse(s, ErrorCodes::Yes, true),
67+
LangString::parse(s, ErrorCodes::Yes, true, None),
6868
LangString {
6969
should_panic,
7070
no_run,

‎src/librustdoc/markdown.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub fn test(mut options: Options, diag: &rustc_errors::Handler) -> i32 {
153153
collector.set_position(DUMMY_SP);
154154
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
155155

156-
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores);
156+
find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None);
157157

158158
options.test_args.insert(0, "rustdoctest".to_string());
159159
testing::test_main(

‎src/librustdoc/passes/check_code_block_syntax.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::clean;
1010
use crate::core::DocContext;
1111
use crate::fold::DocFolder;
1212
use crate::html::markdown::{self, RustCodeBlock};
13-
use crate::passes::Pass;
13+
use crate::passes::{span_of_attrs, Pass};
1414

1515
pub const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
1616
name: "check-code-block-syntax",
@@ -114,7 +114,9 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
114114
impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
115115
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
116116
if let Some(dox) = &item.attrs.collapsed_doc_value() {
117-
for code_block in markdown::rust_code_blocks(&dox) {
117+
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
118+
let extra = crate::html::markdown::ExtraInfo::new_did(&self.cx.tcx, item.def_id, sp);
119+
for code_block in markdown::rust_code_blocks(&dox, &extra) {
118120
self.check_rust_syntax(&item, &dox, code_block);
119121
}
120122
}

‎src/librustdoc/passes/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ pub fn look_for_tests<'tcx>(
338338

339339
let mut tests = Tests { found_tests: 0 };
340340

341-
find_testable_code(&dox, &mut tests, ErrorCodes::No, false);
341+
find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
342342

343343
if check_missing_code && tests.found_tests == 0 {
344344
let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());

‎src/librustdoc/test.rs

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ use rustc_errors::ErrorReported;
55
use rustc_feature::UnstableFeatures;
66
use rustc_hir as hir;
77
use rustc_hir::intravisit;
8+
use rustc_hir::{HirId, CRATE_HIR_ID};
89
use rustc_interface::interface;
910
use rustc_middle::hir::map::Map;
10-
use rustc_session::{self, config, DiagnosticOutput, Session};
11+
use rustc_middle::ty::TyCtxt;
12+
use rustc_session::{self, config, lint, DiagnosticOutput, Session};
1113
use rustc_span::edition::Edition;
1214
use rustc_span::source_map::SourceMap;
1315
use rustc_span::symbol::sym;
@@ -25,6 +27,7 @@ use tempfile::Builder as TempFileBuilder;
2527
use crate::clean::Attributes;
2628
use crate::config::Options;
2729
use crate::html::markdown::{self, ErrorCodes, Ignore, LangString};
30+
use crate::passes::span_of_attrs;
2831

2932
#[derive(Clone, Default)]
3033
pub struct TestOptions {
@@ -40,6 +43,45 @@ pub struct TestOptions {
4043
pub fn run(options: Options) -> i32 {
4144
let input = config::Input::File(options.input.clone());
4245

46+
let warnings_lint_name = lint::builtin::WARNINGS.name;
47+
let invalid_codeblock_attribute_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTE.name;
48+
49+
// In addition to those specific lints, we also need to whitelist those given through
50+
// command line, otherwise they'll get ignored and we don't want that.
51+
let mut whitelisted_lints =
52+
vec![warnings_lint_name.to_owned(), invalid_codeblock_attribute_name.to_owned()];
53+
54+
whitelisted_lints.extend(options.lint_opts.iter().map(|(lint, _)| lint).cloned());
55+
56+
let lints = || {
57+
lint::builtin::HardwiredLints::get_lints()
58+
.into_iter()
59+
.chain(rustc_lint::SoftLints::get_lints().into_iter())
60+
};
61+
62+
let lint_opts = lints()
63+
.filter_map(|lint| {
64+
if lint.name == warnings_lint_name || lint.name == invalid_codeblock_attribute_name {
65+
None
66+
} else {
67+
Some((lint.name_lower(), lint::Allow))
68+
}
69+
})
70+
.chain(options.lint_opts.clone().into_iter())
71+
.collect::<Vec<_>>();
72+
73+
let lint_caps = lints()
74+
.filter_map(|lint| {
75+
// We don't want to whitelist *all* lints so let's
76+
// ignore those ones.
77+
if whitelisted_lints.iter().any(|l| lint.name == l) {
78+
None
79+
} else {
80+
Some((lint::LintId::of(lint), lint::Allow))
81+
}
82+
})
83+
.collect();
84+
4385
let crate_types = if options.proc_macro_crate {
4486
vec![config::CrateType::ProcMacro]
4587
} else {
@@ -50,10 +92,11 @@ pub fn run(options: Options) -> i32 {
5092
maybe_sysroot: options.maybe_sysroot.clone(),
5193
search_paths: options.libs.clone(),
5294
crate_types,
95+
lint_opts: if !options.display_warnings { lint_opts } else { vec![] },
96+
lint_cap: Some(options.lint_cap.clone().unwrap_or_else(|| lint::Forbid)),
5397
cg: options.codegen_options.clone(),
5498
externs: options.externs.clone(),
5599
unstable_features: UnstableFeatures::from_environment(),
56-
lint_cap: Some(rustc_session::lint::Level::Allow),
57100
actually_rustdoc: true,
58101
debugging_opts: config::DebuggingOptions { ..config::basic_debugging_options() },
59102
edition: options.edition,
@@ -75,7 +118,7 @@ pub fn run(options: Options) -> i32 {
75118
diagnostic_output: DiagnosticOutput::Default,
76119
stderr: None,
77120
crate_name: options.crate_name.clone(),
78-
lint_caps: Default::default(),
121+
lint_caps,
79122
register_lints: None,
80123
override_queries: None,
81124
registry: rustc_driver::diagnostics_registry(),
@@ -105,17 +148,25 @@ pub fn run(options: Options) -> i32 {
105148

106149
global_ctxt.enter(|tcx| {
107150
let krate = tcx.hir().krate();
151+
108152
let mut hir_collector = HirCollector {
109153
sess: compiler.session(),
110154
collector: &mut collector,
111155
map: tcx.hir(),
112156
codes: ErrorCodes::from(
113157
compiler.session().opts.unstable_features.is_nightly_build(),
114158
),
159+
tcx,
115160
};
116-
hir_collector.visit_testable("".to_string(), &krate.item.attrs, |this| {
117-
intravisit::walk_crate(this, krate);
118-
});
161+
hir_collector.visit_testable(
162+
"".to_string(),
163+
&krate.item.attrs,
164+
CRATE_HIR_ID,
165+
krate.item.span,
166+
|this| {
167+
intravisit::walk_crate(this, krate);
168+
},
169+
);
119170
});
120171
compiler.session().abort_if_errors();
121172

@@ -881,18 +932,21 @@ impl Tester for Collector {
881932
}
882933
}
883934

884-
struct HirCollector<'a, 'hir> {
935+
struct HirCollector<'a, 'hir, 'tcx> {
885936
sess: &'a Session,
886937
collector: &'a mut Collector,
887938
map: Map<'hir>,
888939
codes: ErrorCodes,
940+
tcx: TyCtxt<'tcx>,
889941
}
890942

891-
impl<'a, 'hir> HirCollector<'a, 'hir> {
943+
impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
892944
fn visit_testable<F: FnOnce(&mut Self)>(
893945
&mut self,
894946
name: String,
895947
attrs: &[ast::Attribute],
948+
hir_id: HirId,
949+
sp: Span,
896950
nested: F,
897951
) {
898952
let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs);
@@ -918,6 +972,11 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
918972
self.collector,
919973
self.codes,
920974
self.collector.enable_per_target_ignores,
975+
Some(&crate::html::markdown::ExtraInfo::new(
976+
&self.tcx,
977+
hir_id,
978+
span_of_attrs(&attrs).unwrap_or(sp),
979+
)),
921980
);
922981
}
923982

@@ -929,7 +988,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
929988
}
930989
}
931990

932-
impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
991+
impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> {
933992
type Map = Map<'hir>;
934993

935994
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
@@ -943,25 +1002,25 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
9431002
item.ident.to_string()
9441003
};
9451004

946-
self.visit_testable(name, &item.attrs, |this| {
1005+
self.visit_testable(name, &item.attrs, item.hir_id, item.span, |this| {
9471006
intravisit::walk_item(this, item);
9481007
});
9491008
}
9501009

9511010
fn visit_trait_item(&mut self, item: &'hir hir::TraitItem) {
952-
self.visit_testable(item.ident.to_string(), &item.attrs, |this| {
1011+
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
9531012
intravisit::walk_trait_item(this, item);
9541013
});
9551014
}
9561015

9571016
fn visit_impl_item(&mut self, item: &'hir hir::ImplItem) {
958-
self.visit_testable(item.ident.to_string(), &item.attrs, |this| {
1017+
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
9591018
intravisit::walk_impl_item(this, item);
9601019
});
9611020
}
9621021

9631022
fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) {
964-
self.visit_testable(item.ident.to_string(), &item.attrs, |this| {
1023+
self.visit_testable(item.ident.to_string(), &item.attrs, item.hir_id, item.span, |this| {
9651024
intravisit::walk_foreign_item(this, item);
9661025
});
9671026
}
@@ -972,19 +1031,25 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
9721031
g: &'hir hir::Generics,
9731032
item_id: hir::HirId,
9741033
) {
975-
self.visit_testable(v.ident.to_string(), &v.attrs, |this| {
1034+
self.visit_testable(v.ident.to_string(), &v.attrs, v.id, v.span, |this| {
9761035
intravisit::walk_variant(this, v, g, item_id);
9771036
});
9781037
}
9791038

9801039
fn visit_struct_field(&mut self, f: &'hir hir::StructField) {
981-
self.visit_testable(f.ident.to_string(), &f.attrs, |this| {
1040+
self.visit_testable(f.ident.to_string(), &f.attrs, f.hir_id, f.span, |this| {
9821041
intravisit::walk_struct_field(this, f);
9831042
});
9841043
}
9851044

9861045
fn visit_macro_def(&mut self, macro_def: &'hir hir::MacroDef) {
987-
self.visit_testable(macro_def.ident.to_string(), &macro_def.attrs, |_| ());
1046+
self.visit_testable(
1047+
macro_def.ident.to_string(),
1048+
&macro_def.attrs,
1049+
macro_def.hir_id,
1050+
macro_def.span,
1051+
|_| (),
1052+
);
9881053
}
9891054
}
9901055

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// compile-flags:--test
2+
3+
#![deny(invalid_codeblock_attribute)]
4+
5+
/// foo
6+
///
7+
/// ```compile-fail,compilefail,comPile_fail
8+
/// boo
9+
/// ```
10+
pub fn foo() {}
11+
12+
/// bar
13+
///
14+
/// ```should-panic,shouldpanic,shOuld_panic
15+
/// boo
16+
/// ```
17+
pub fn bar() {}
18+
19+
/// foobar
20+
///
21+
/// ```no-run,norun,nO_run
22+
/// boo
23+
/// ```
24+
pub fn foobar() {}
25+
26+
/// barfoo
27+
///
28+
/// ```allow-fail,allowfail,allOw_fail
29+
/// boo
30+
/// ```
31+
pub fn barfoo() {}
32+
33+
/// b
34+
///
35+
/// ```test-harness,testharness,tesT_harness
36+
/// boo
37+
/// ```
38+
pub fn b() {}
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
error: unknown attribute `compile-fail`. Did you mean `compile_fail`?
2+
--> $DIR/check-attr-test.rs:5:1
3+
|
4+
5 | / /// foo
5+
6 | | ///
6+
7 | | /// ```compile-fail,compilefail,comPile_fail
7+
8 | | /// boo
8+
9 | | /// ```
9+
| |_______^
10+
|
11+
note: the lint level is defined here
12+
--> $DIR/check-attr-test.rs:3:9
13+
|
14+
3 | #![deny(invalid_codeblock_attribute)]
15+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
16+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
17+
18+
error: unknown attribute `compilefail`. Did you mean `compile_fail`?
19+
--> $DIR/check-attr-test.rs:5:1
20+
|
21+
5 | / /// foo
22+
6 | | ///
23+
7 | | /// ```compile-fail,compilefail,comPile_fail
24+
8 | | /// boo
25+
9 | | /// ```
26+
| |_______^
27+
|
28+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
29+
30+
error: unknown attribute `comPile_fail`. Did you mean `compile_fail`?
31+
--> $DIR/check-attr-test.rs:5:1
32+
|
33+
5 | / /// foo
34+
6 | | ///
35+
7 | | /// ```compile-fail,compilefail,comPile_fail
36+
8 | | /// boo
37+
9 | | /// ```
38+
| |_______^
39+
|
40+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
41+
42+
error: unknown attribute `should-panic`. Did you mean `should_panic`?
43+
--> $DIR/check-attr-test.rs:12:1
44+
|
45+
12 | / /// bar
46+
13 | | ///
47+
14 | | /// ```should-panic,shouldpanic,shOuld_panic
48+
15 | | /// boo
49+
16 | | /// ```
50+
| |_______^
51+
|
52+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
53+
54+
error: unknown attribute `shouldpanic`. Did you mean `should_panic`?
55+
--> $DIR/check-attr-test.rs:12:1
56+
|
57+
12 | / /// bar
58+
13 | | ///
59+
14 | | /// ```should-panic,shouldpanic,shOuld_panic
60+
15 | | /// boo
61+
16 | | /// ```
62+
| |_______^
63+
|
64+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
65+
66+
error: unknown attribute `shOuld_panic`. Did you mean `should_panic`?
67+
--> $DIR/check-attr-test.rs:12:1
68+
|
69+
12 | / /// bar
70+
13 | | ///
71+
14 | | /// ```should-panic,shouldpanic,shOuld_panic
72+
15 | | /// boo
73+
16 | | /// ```
74+
| |_______^
75+
|
76+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
77+
78+
error: unknown attribute `no-run`. Did you mean `no_run`?
79+
--> $DIR/check-attr-test.rs:19:1
80+
|
81+
19 | / /// foobar
82+
20 | | ///
83+
21 | | /// ```no-run,norun,nO_run
84+
22 | | /// boo
85+
23 | | /// ```
86+
| |_______^
87+
|
88+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
89+
90+
error: unknown attribute `norun`. Did you mean `no_run`?
91+
--> $DIR/check-attr-test.rs:19:1
92+
|
93+
19 | / /// foobar
94+
20 | | ///
95+
21 | | /// ```no-run,norun,nO_run
96+
22 | | /// boo
97+
23 | | /// ```
98+
| |_______^
99+
|
100+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
101+
102+
error: unknown attribute `nO_run`. Did you mean `no_run`?
103+
--> $DIR/check-attr-test.rs:19:1
104+
|
105+
19 | / /// foobar
106+
20 | | ///
107+
21 | | /// ```no-run,norun,nO_run
108+
22 | | /// boo
109+
23 | | /// ```
110+
| |_______^
111+
|
112+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
113+
114+
error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
115+
--> $DIR/check-attr-test.rs:26:1
116+
|
117+
26 | / /// barfoo
118+
27 | | ///
119+
28 | | /// ```allow-fail,allowfail,allOw_fail
120+
29 | | /// boo
121+
30 | | /// ```
122+
| |_______^
123+
|
124+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
125+
126+
error: unknown attribute `allowfail`. Did you mean `allow_fail`?
127+
--> $DIR/check-attr-test.rs:26:1
128+
|
129+
26 | / /// barfoo
130+
27 | | ///
131+
28 | | /// ```allow-fail,allowfail,allOw_fail
132+
29 | | /// boo
133+
30 | | /// ```
134+
| |_______^
135+
|
136+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
137+
138+
error: unknown attribute `allOw_fail`. Did you mean `allow_fail`?
139+
--> $DIR/check-attr-test.rs:26:1
140+
|
141+
26 | / /// barfoo
142+
27 | | ///
143+
28 | | /// ```allow-fail,allowfail,allOw_fail
144+
29 | | /// boo
145+
30 | | /// ```
146+
| |_______^
147+
|
148+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
149+
150+
error: unknown attribute `test-harness`. Did you mean `test_harness`?
151+
--> $DIR/check-attr-test.rs:33:1
152+
|
153+
33 | / /// b
154+
34 | | ///
155+
35 | | /// ```test-harness,testharness,tesT_harness
156+
36 | | /// boo
157+
37 | | /// ```
158+
| |_______^
159+
|
160+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
161+
162+
error: unknown attribute `testharness`. Did you mean `test_harness`?
163+
--> $DIR/check-attr-test.rs:33:1
164+
|
165+
33 | / /// b
166+
34 | | ///
167+
35 | | /// ```test-harness,testharness,tesT_harness
168+
36 | | /// boo
169+
37 | | /// ```
170+
| |_______^
171+
|
172+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
173+
174+
error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
175+
--> $DIR/check-attr-test.rs:33:1
176+
|
177+
33 | / /// b
178+
34 | | ///
179+
35 | | /// ```test-harness,testharness,tesT_harness
180+
36 | | /// boo
181+
37 | | /// ```
182+
| |_______^
183+
|
184+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
185+
186+
error: aborting due to 15 previous errors
187+

‎src/test/rustdoc-ui/check-attr.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#![deny(invalid_codeblock_attribute)]
2+
3+
/// foo
4+
//~^ ERROR
5+
//~^^ ERROR
6+
//~^^^ ERROR
7+
///
8+
/// ```compile-fail,compilefail,comPile_fail
9+
/// boo
10+
/// ```
11+
pub fn foo() {}
12+
13+
/// bar
14+
//~^ ERROR
15+
//~^^ ERROR
16+
//~^^^ ERROR
17+
///
18+
/// ```should-panic,shouldpanic,sHould_panic
19+
/// boo
20+
/// ```
21+
pub fn bar() {}
22+
23+
/// foobar
24+
//~^ ERROR
25+
//~^^ ERROR
26+
//~^^^ ERROR
27+
///
28+
/// ```no-run,norun,no_Run
29+
/// boo
30+
/// ```
31+
pub fn foobar() {}
32+
33+
/// barfoo
34+
//~^ ERROR
35+
//~^^ ERROR
36+
//~^^^ ERROR
37+
///
38+
/// ```allow-fail,allowfail,alLow_fail
39+
/// boo
40+
/// ```
41+
pub fn barfoo() {}
42+
43+
/// b
44+
//~^ ERROR
45+
//~^^ ERROR
46+
//~^^^ ERROR
47+
///
48+
/// ```test-harness,testharness,teSt_harness
49+
/// boo
50+
/// ```
51+
pub fn b() {}

‎src/test/rustdoc-ui/check-attr.stderr

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
error: unknown attribute `compile-fail`. Did you mean `compile_fail`?
2+
--> $DIR/check-attr.rs:3:1
3+
|
4+
LL | / /// foo
5+
LL | |
6+
LL | |
7+
LL | |
8+
... |
9+
LL | | /// boo
10+
LL | | /// ```
11+
| |_______^
12+
|
13+
note: the lint level is defined here
14+
--> $DIR/check-attr.rs:1:9
15+
|
16+
LL | #![deny(invalid_codeblock_attribute)]
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
19+
20+
error: unknown attribute `compilefail`. Did you mean `compile_fail`?
21+
--> $DIR/check-attr.rs:3:1
22+
|
23+
LL | / /// foo
24+
LL | |
25+
LL | |
26+
LL | |
27+
... |
28+
LL | | /// boo
29+
LL | | /// ```
30+
| |_______^
31+
|
32+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
33+
34+
error: unknown attribute `comPile_fail`. Did you mean `compile_fail`?
35+
--> $DIR/check-attr.rs:3:1
36+
|
37+
LL | / /// foo
38+
LL | |
39+
LL | |
40+
LL | |
41+
... |
42+
LL | | /// boo
43+
LL | | /// ```
44+
| |_______^
45+
|
46+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully
47+
48+
error: unknown attribute `should-panic`. Did you mean `should_panic`?
49+
--> $DIR/check-attr.rs:13:1
50+
|
51+
LL | / /// bar
52+
LL | |
53+
LL | |
54+
LL | |
55+
... |
56+
LL | | /// boo
57+
LL | | /// ```
58+
| |_______^
59+
|
60+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
61+
62+
error: unknown attribute `shouldpanic`. Did you mean `should_panic`?
63+
--> $DIR/check-attr.rs:13:1
64+
|
65+
LL | / /// bar
66+
LL | |
67+
LL | |
68+
LL | |
69+
... |
70+
LL | | /// boo
71+
LL | | /// ```
72+
| |_______^
73+
|
74+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
75+
76+
error: unknown attribute `sHould_panic`. Did you mean `should_panic`?
77+
--> $DIR/check-attr.rs:13:1
78+
|
79+
LL | / /// bar
80+
LL | |
81+
LL | |
82+
LL | |
83+
... |
84+
LL | | /// boo
85+
LL | | /// ```
86+
| |_______^
87+
|
88+
= help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
89+
90+
error: unknown attribute `no-run`. Did you mean `no_run`?
91+
--> $DIR/check-attr.rs:23:1
92+
|
93+
LL | / /// foobar
94+
LL | |
95+
LL | |
96+
LL | |
97+
... |
98+
LL | | /// boo
99+
LL | | /// ```
100+
| |_______^
101+
|
102+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
103+
104+
error: unknown attribute `norun`. Did you mean `no_run`?
105+
--> $DIR/check-attr.rs:23:1
106+
|
107+
LL | / /// foobar
108+
LL | |
109+
LL | |
110+
LL | |
111+
... |
112+
LL | | /// boo
113+
LL | | /// ```
114+
| |_______^
115+
|
116+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
117+
118+
error: unknown attribute `no_Run`. Did you mean `no_run`?
119+
--> $DIR/check-attr.rs:23:1
120+
|
121+
LL | / /// foobar
122+
LL | |
123+
LL | |
124+
LL | |
125+
... |
126+
LL | | /// boo
127+
LL | | /// ```
128+
| |_______^
129+
|
130+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
131+
132+
error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
133+
--> $DIR/check-attr.rs:33:1
134+
|
135+
LL | / /// barfoo
136+
LL | |
137+
LL | |
138+
LL | |
139+
... |
140+
LL | | /// boo
141+
LL | | /// ```
142+
| |_______^
143+
|
144+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
145+
146+
error: unknown attribute `allowfail`. Did you mean `allow_fail`?
147+
--> $DIR/check-attr.rs:33:1
148+
|
149+
LL | / /// barfoo
150+
LL | |
151+
LL | |
152+
LL | |
153+
... |
154+
LL | | /// boo
155+
LL | | /// ```
156+
| |_______^
157+
|
158+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
159+
160+
error: unknown attribute `alLow_fail`. Did you mean `allow_fail`?
161+
--> $DIR/check-attr.rs:33:1
162+
|
163+
LL | / /// barfoo
164+
LL | |
165+
LL | |
166+
LL | |
167+
... |
168+
LL | | /// boo
169+
LL | | /// ```
170+
| |_______^
171+
|
172+
= help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
173+
174+
error: unknown attribute `test-harness`. Did you mean `test_harness`?
175+
--> $DIR/check-attr.rs:43:1
176+
|
177+
LL | / /// b
178+
LL | |
179+
LL | |
180+
LL | |
181+
... |
182+
LL | | /// boo
183+
LL | | /// ```
184+
| |_______^
185+
|
186+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
187+
188+
error: unknown attribute `testharness`. Did you mean `test_harness`?
189+
--> $DIR/check-attr.rs:43:1
190+
|
191+
LL | / /// b
192+
LL | |
193+
LL | |
194+
LL | |
195+
... |
196+
LL | | /// boo
197+
LL | | /// ```
198+
| |_______^
199+
|
200+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
201+
202+
error: unknown attribute `teSt_harness`. Did you mean `test_harness`?
203+
--> $DIR/check-attr.rs:43:1
204+
|
205+
LL | / /// b
206+
LL | |
207+
LL | |
208+
LL | |
209+
... |
210+
LL | | /// boo
211+
LL | | /// ```
212+
| |_______^
213+
|
214+
= help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
215+
216+
error: aborting due to 15 previous errors
217+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
pub enum ErrorHandled {
2+
Reported,
3+
TooGeneric,
4+
}
5+
6+
impl ErrorHandled {
7+
pub fn assert_reported(self) {
8+
match self {
9+
ErrorHandled::Reported => {}
10+
ErrorHandled::TooGeneric => panic!(),
11+
}
12+
}
13+
}
14+
15+
fn struct_generic(x: Vec<i32>) {
16+
for v in x {
17+
println!("{}", v);
18+
}
19+
}
20+
} //~ ERROR unexpected closing delimiter: `}`
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: unexpected closing delimiter: `}`
2+
--> $DIR/issue-70583-block-is-empty-1.rs:20:1
3+
|
4+
LL | fn struct_generic(x: Vec<i32>) {
5+
| - this opening brace...
6+
...
7+
LL | }
8+
| - ...matches this closing brace
9+
LL | }
10+
| ^ unexpected closing delimiter
11+
12+
error: aborting due to previous error
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pub enum ErrorHandled {
2+
Reported,
3+
TooGeneric,
4+
}
5+
6+
impl ErrorHandled {
7+
pub fn assert_reported(self) {
8+
match self {
9+
ErrorHandled::Reported => {}}
10+
//^~ ERROR block is empty, you might have not meant to close it
11+
ErrorHandled::TooGeneric => panic!(),
12+
}
13+
}
14+
} //~ ERROR unexpected closing delimiter: `}`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: unexpected closing delimiter: `}`
2+
--> $DIR/issue-70583-block-is-empty-2.rs:14:1
3+
|
4+
LL | ErrorHandled::Reported => {}}
5+
| -- block is empty, you might have not meant to close it
6+
...
7+
LL | }
8+
| ^ unexpected closing delimiter
9+
10+
error: aborting due to previous error
11+

‎src/test/ui/parser/macro-mismatched-delim-paren-brace.stderr

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
error: unexpected closing delimiter: `}`
22
--> $DIR/macro-mismatched-delim-paren-brace.rs:5:1
33
|
4+
LL | fn main() {
5+
| - this opening brace...
6+
...
7+
LL | }
8+
| - ...matches this closing brace
49
LL | }
510
| ^ unexpected closing delimiter
611

‎src/test/ui/parser/mismatched-delim-brace-empty-block.stderr

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
error: unexpected closing delimiter: `}`
22
--> $DIR/mismatched-delim-brace-empty-block.rs:5:1
33
|
4+
LL | fn main() {
5+
| - this opening brace...
6+
LL |
7+
LL | }
8+
| - ...matches this closing brace
9+
LL | let _ = ();
410
LL | }
511
| ^ unexpected closing delimiter
612

0 commit comments

Comments
 (0)
This repository has been archived.