From b73ad09dfd8ec347799da54f12059e69fa355d1d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 3 May 2021 17:32:06 -0400 Subject: [PATCH 1/9] Remove SpanInterner::get - It's used exactly once, so it's trivial to replace - It doesn't match the normal convention for containers: normally `get()` returns and option and indexing panics. Instead `get()` panicked and there's no indexing operation available. --- compiler/rustc_span/src/span_encoding.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index ceb9b59b13ad..5ea39b343b5c 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -102,7 +102,7 @@ impl Span { // Interned format. debug_assert!(self.ctxt_or_zero == 0); let index = self.base_or_index; - with_span_interner(|interner| *interner.get(index)) + with_span_interner(|interner| interner.spans[index as usize]) } } } @@ -117,11 +117,6 @@ impl SpanInterner { let (index, _) = self.spans.insert_full(*span_data); index as u32 } - - #[inline] - fn get(&self, index: u32) -> &SpanData { - &self.spans[index as usize] - } } // If an interner exists, return it. Otherwise, prepare a fresh one. From 4dddc3818ec6a618ba85a07ca4fdede56f7f0282 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 May 2021 15:11:18 +0200 Subject: [PATCH 2/9] fix null pointer error messages --- .../rustc_middle/src/mir/interpret/error.rs | 19 +++++++++++-------- .../const-eval/ub-wide-ptr.64bit.stderr | 2 +- src/test/ui/consts/offset_from_ub.stderr | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index ea582d470f90..9c3bed6ec0ad 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -170,22 +170,25 @@ impl fmt::Display for InvalidProgramInfo<'_> { /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] pub enum CheckInAllocMsg { + /// We are access memory. MemoryAccessTest, + /// We are doing pointer arithmetic. PointerArithmeticTest, + /// None of the above -- generic/unspecific inbounds test. InboundsTest, } impl fmt::Display for CheckInAllocMsg { /// When this is printed as an error the context looks like this - /// "{test name} failed: pointer must be in-bounds at offset..." + /// "{msg}pointer must be in-bounds at offset..." fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}", match *self { - CheckInAllocMsg::MemoryAccessTest => "memory access", - CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic", - CheckInAllocMsg::InboundsTest => "inbounds test", + CheckInAllocMsg::MemoryAccessTest => "memory access failed: ", + CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ", + CheckInAllocMsg::InboundsTest => "", } ) } @@ -299,18 +302,18 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { } PointerOutOfBounds { ptr, msg, allocation_size } => write!( f, - "{} failed: pointer must be in-bounds at offset {}, \ + "{}pointer must be in-bounds at offset {}, \ but is outside bounds of {} which has size {}", msg, ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes() ), - DanglingIntPointer(_, CheckInAllocMsg::InboundsTest) => { - write!(f, "null pointer is not allowed for this operation") + DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => { + write!(f, "null pointer is not a valid pointer for this operation") } DanglingIntPointer(i, msg) => { - write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i) + write!(f, "{}0x{:x} is not a valid pointer", msg, i) } AlignmentCheckFailed { required, has } => write!( f, diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr index 39c565427628..bb95343a786a 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr @@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:135:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:139:5 diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index d5d213f9c79d..4254cda2a008 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -74,7 +74,7 @@ error: any use of this value will cause an error LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | null pointer is not allowed for this operation + | null pointer is not a valid pointer for this operation | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14 | From 919bfd86d94e039b016a63d3e91bc16dd94a92bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 May 2021 16:51:00 +0200 Subject: [PATCH 3/9] Don't stop running rustdoc-gui tests at first failure --- src/bootstrap/test.rs | 30 +++++------------- src/tools/rustdoc-gui/tester.js | 54 ++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index c98398cf1d25..df467bebe748 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -831,28 +831,14 @@ impl Step for RustdocGUI { command.arg("src/test/rustdoc-gui/lib.rs").arg("-o").arg(&out_dir); builder.run(&mut command); - let mut tests = Vec::new(); - for file in fs::read_dir("src/test/rustdoc-gui").unwrap() { - let file = file.unwrap(); - let file_path = file.path(); - let file_name = file.file_name(); - - if !file_name.to_str().unwrap().ends_with(".goml") { - continue; - } - tests.push(file_path); - } - tests.sort_unstable(); - for test in tests { - let mut command = Command::new(&nodejs); - command - .arg("src/tools/rustdoc-gui/tester.js") - .arg("--doc-folder") - .arg(out_dir.join("test_docs")) - .arg("--test-file") - .arg(test); - builder.run(&mut command); - } + let mut command = Command::new(&nodejs); + command + .arg("src/tools/rustdoc-gui/tester.js") + .arg("--doc-folder") + .arg(out_dir.join("test_docs")) + .arg("--tests-folder") + .arg("src/test/rustdoc-gui"); + builder.run(&mut command); } else { builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests"); } diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index a67e2455478f..298fc7519fac 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -3,29 +3,30 @@ // ``` // npm install browser-ui-test // ``` -const path = require('path'); +const fs = require("fs"); +const path = require("path"); const {Options, runTest} = require('browser-ui-test'); function showHelp() { console.log("rustdoc-js options:"); console.log(" --doc-folder [PATH] : location of the generated doc folder"); console.log(" --help : show this message then quit"); - console.log(" --test-file [PATH] : location of the JS test file"); + console.log(" --tests-folder [PATH] : location of the .GOML tests folder"); } function parseOptions(args) { var opts = { "doc_folder": "", - "test_file": "", + "tests_folder": "", }; var correspondances = { "--doc-folder": "doc_folder", - "--test-file": "test_file", + "--tests-folder": "tests_folder", }; for (var i = 0; i < args.length; ++i) { if (args[i] === "--doc-folder" - || args[i] === "--test-file") { + || args[i] === "--tests-folder") { i += 1; if (i >= args.length) { console.log("Missing argument after `" + args[i - 1] + "` option."); @@ -41,8 +42,8 @@ function parseOptions(args) { return null; } } - if (opts["test_file"].length < 1) { - console.log("Missing `--test-file` option."); + if (opts["tests_folder"].length < 1) { + console.log("Missing `--tests-folder` option."); } else if (opts["doc_folder"].length < 1) { console.log("Missing `--doc-folder` option."); } else { @@ -51,15 +52,8 @@ function parseOptions(args) { return null; } -function checkFile(test_file, opts, loaded, index) { - const test_name = path.basename(test_file, ".js"); - - process.stdout.write('Checking "' + test_name + '" ... '); - return runChecks(test_file, loaded, index); -} - -function main(argv) { - var opts = parseOptions(argv.slice(2)); +async function main(argv) { + let opts = parseOptions(argv.slice(2)); if (opts === null) { process.exit(1); } @@ -68,7 +62,7 @@ function main(argv) { try { // This is more convenient that setting fields one by one. options.parseArguments([ - '--no-screenshot', + "--no-screenshot", "--variable", "DOC_PATH", opts["doc_folder"], ]); } catch (error) { @@ -76,14 +70,26 @@ function main(argv) { process.exit(1); } - runTest(opts["test_file"], options).then(out => { - const [output, nb_failures] = out; - console.log(output); - process.exit(nb_failures); - }).catch(err => { - console.error(err); + let failed = false; + let files = fs.readdirSync(opts["tests_folder"]).filter(file => path.extname(file) == ".goml"); + + files.sort(); + for (var i = 0; i < files.length; ++i) { + const testPath = path.join(opts["tests_folder"], files[i]); + await runTest(testPath, options).then(out => { + const [output, nb_failures] = out; + console.log(output); + if (nb_failures > 0) { + failed = true; + } + }).catch(err => { + console.error(err); + failed = true; + }); + } + if (failed) { process.exit(1); - }); + } } main(process.argv); From 6386656d45313e5787a1a6025ed02157dea280c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 May 2021 17:24:50 +0200 Subject: [PATCH 4/9] bless 32bit --- src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr index 404ce409d93b..c69674a6721b 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr @@ -296,7 +296,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:135:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not allowed for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation error[E0080]: could not evaluate static initializer --> $DIR/ub-wide-ptr.rs:139:5 From d9a58f4c87acce4c413b6bfb93916823bafbd68b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 7 May 2021 17:32:40 +0100 Subject: [PATCH 5/9] Use `path.exists()` instead of `fs::metadata(path).is_ok()` It's more explicit and allows platforms to optimize the existence check. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- compiler/rustc_span/src/source_map.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 401d379b0d16..fecea9f952b4 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -764,7 +764,7 @@ impl<'a> Linker for MsvcLinker<'a> { // check to see if the file is there and just omit linking to it if it's // not present. let name = format!("{}.dll.lib", lib); - if fs::metadata(&path.join(&name)).is_ok() { + if path.join(&name).exists() { self.cmd.arg(name); } } diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index f612d1425b93..e365844980b4 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -109,7 +109,7 @@ pub struct RealFileLoader; impl FileLoader for RealFileLoader { fn file_exists(&self, path: &Path) -> bool { - fs::metadata(path).is_ok() + path.exists() } fn read_file(&self, path: &Path) -> io::Result { From cecb3be49a03589a8651cd7b1250db139544dc5d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 16 Sep 2020 23:10:05 +0200 Subject: [PATCH 6/9] Improve diagnostics for functions in `struct` definitions --- compiler/rustc_parse/src/parser/item.rs | 25 ++++++++++++++++- compiler/rustc_parse/src/parser/mod.rs | 36 ++++++++++++------------- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index acf3867cf892..60a6cb28a177 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1402,7 +1402,7 @@ impl<'a> Parser<'a> { vis: Visibility, attrs: Vec, ) -> PResult<'a, FieldDef> { - let name = self.parse_ident_common(false)?; + let name = self.parse_field_ident(lo)?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(FieldDef { @@ -1416,6 +1416,29 @@ impl<'a> Parser<'a> { }) } + /// Parses a field identifier. Specialized version of `parse_ident_common` + /// for better diagnostics and suggestions. + fn parse_field_ident(&mut self, lo: Span) -> PResult<'a, Ident> { + let (ident, is_raw) = self.ident_or_err()?; + if !is_raw && ident.is_reserved() { + let err = if self.check_fn_front_matter(false) { + let _ = self.parse_fn(&mut Vec::new(), |_| true, lo); + let mut err = self.struct_span_err( + lo.to(self.prev_token.span), + "functions are not allowed in struct definitions", + ); + err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks"); + err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); + err + } else { + self.expected_ident_found() + }; + return Err(err); + } + self.bump(); + Ok(ident) + } + /// Parses a declarative macro 2.0 definition. /// The `macro` keyword has already been parsed. /// ``` diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index ed95a5661b18..74481e236f31 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -522,27 +522,27 @@ impl<'a> Parser<'a> { self.parse_ident_common(true) } + fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> { + self.token.ident().ok_or_else(|| match self.prev_token.kind { + TokenKind::DocComment(..) => { + self.span_fatal_err(self.prev_token.span, Error::UselessDocComment) + } + _ => self.expected_ident_found(), + }) + } + fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - match self.token.ident() { - Some((ident, is_raw)) => { - if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found(); - if recover { - err.emit(); - } else { - return Err(err); - } - } - self.bump(); - Ok(ident) + let (ident, is_raw) = self.ident_or_err()?; + if !is_raw && ident.is_reserved() { + let mut err = self.expected_ident_found(); + if recover { + err.emit(); + } else { + return Err(err); } - _ => Err(match self.prev_token.kind { - TokenKind::DocComment(..) => { - self.span_fatal_err(self.prev_token.span, Error::UselessDocComment) - } - _ => self.expected_ident_found(), - }), } + self.bump(); + Ok(ident) } /// Checks if the next token is `tok`, and returns `true` if so. From 1e642f0a61b2b44cf4c4e2c174256f10520bcea1 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 17 Sep 2020 18:44:09 +0200 Subject: [PATCH 7/9] Add basic test --- src/test/ui/structs/struct-fn-in-definition.rs | 14 ++++++++++++++ src/test/ui/structs/struct-fn-in-definition.stderr | 11 +++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/structs/struct-fn-in-definition.rs create mode 100644 src/test/ui/structs/struct-fn-in-definition.stderr diff --git a/src/test/ui/structs/struct-fn-in-definition.rs b/src/test/ui/structs/struct-fn-in-definition.rs new file mode 100644 index 000000000000..d841051bdd05 --- /dev/null +++ b/src/test/ui/structs/struct-fn-in-definition.rs @@ -0,0 +1,14 @@ +// It might be intuitive for a user coming from languages like Java +// to declare a method directly in a struct's definition. Make sure +// rustc can give a helpful suggestion. +// Suggested in issue #76421 + +struct S { + field: usize, + fn do_something() {} + //~^ ERROR functions are not allowed in struct definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + +fn main() {} diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr new file mode 100644 index 000000000000..84d7362e024b --- /dev/null +++ b/src/test/ui/structs/struct-fn-in-definition.stderr @@ -0,0 +1,11 @@ +error: functions are not allowed in struct definitions + --> $DIR/struct-fn-in-definition.rs:5:5 + | +LL | fn do_something() {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: aborting due to previous error + From 6717f81b96aca75f5b811104ae75620274dad35d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 7 May 2021 22:49:47 +0200 Subject: [PATCH 8/9] Also take unions and enums into account --- compiler/rustc_parse/src/parser/item.rs | 33 +++++++++++-------- .../ui/structs/struct-fn-in-definition.rs | 21 +++++++++++- .../ui/structs/struct-fn-in-definition.stderr | 26 ++++++++++++--- 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 60a6cb28a177..20e8b0f6425c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1124,11 +1124,11 @@ impl<'a> Parser<'a> { if !this.recover_nested_adt_item(kw::Enum)? { return Ok((None, TrailingToken::None)); } - let ident = this.parse_ident()?; + let ident = this.parse_field_ident("enum", vlo)?; let struct_def = if this.check(&token::OpenDelim(token::Brace)) { // Parse a struct variant. - let (fields, recovered) = this.parse_record_struct_body()?; + let (fields, recovered) = this.parse_record_struct_body("struct")?; VariantData::Struct(fields, recovered) } else if this.check(&token::OpenDelim(token::Paren)) { VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID) @@ -1182,7 +1182,7 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) } else { // If we see: `struct Foo where T: Copy { ... }` - let (fields, recovered) = self.parse_record_struct_body()?; + let (fields, recovered) = self.parse_record_struct_body("struct")?; VariantData::Struct(fields, recovered) } // No `where` so: `struct Foo;` @@ -1190,7 +1190,7 @@ impl<'a> Parser<'a> { VariantData::Unit(DUMMY_NODE_ID) // Record-style struct definition } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body()?; + let (fields, recovered) = self.parse_record_struct_body("struct")?; VariantData::Struct(fields, recovered) // Tuple-style struct definition with optional where-clause. } else if self.token == token::OpenDelim(token::Paren) { @@ -1220,10 +1220,10 @@ impl<'a> Parser<'a> { let vdata = if self.token.is_keyword(kw::Where) { generics.where_clause = self.parse_where_clause()?; - let (fields, recovered) = self.parse_record_struct_body()?; + let (fields, recovered) = self.parse_record_struct_body("union")?; VariantData::Struct(fields, recovered) } else if self.token == token::OpenDelim(token::Brace) { - let (fields, recovered) = self.parse_record_struct_body()?; + let (fields, recovered) = self.parse_record_struct_body("union")?; VariantData::Struct(fields, recovered) } else { let token_str = super::token_descr(&self.token); @@ -1236,12 +1236,15 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics))) } - fn parse_record_struct_body(&mut self) -> PResult<'a, (Vec, /* recovered */ bool)> { + fn parse_record_struct_body( + &mut self, + adt_ty: &str, + ) -> PResult<'a, (Vec, /* recovered */ bool)> { let mut fields = Vec::new(); let mut recovered = false; if self.eat(&token::OpenDelim(token::Brace)) { while self.token != token::CloseDelim(token::Brace) { - let field = self.parse_field_def().map_err(|e| { + let field = self.parse_field_def(adt_ty).map_err(|e| { self.consume_block(token::Brace, ConsumeClosingDelim::No); recovered = true; e @@ -1294,24 +1297,25 @@ impl<'a> Parser<'a> { } /// Parses an element of a struct declaration. - fn parse_field_def(&mut self) -> PResult<'a, FieldDef> { + fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> { let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; - Ok((this.parse_single_struct_field(lo, vis, attrs)?, TrailingToken::None)) + Ok((this.parse_single_struct_field(adt_ty, lo, vis, attrs)?, TrailingToken::None)) }) } /// Parses a structure field declaration. fn parse_single_struct_field( &mut self, + adt_ty: &str, lo: Span, vis: Visibility, attrs: Vec, ) -> PResult<'a, FieldDef> { let mut seen_comma: bool = false; - let a_var = self.parse_name_and_ty(lo, vis, attrs)?; + let a_var = self.parse_name_and_ty(adt_ty, lo, vis, attrs)?; if self.token == token::Comma { seen_comma = true; } @@ -1398,11 +1402,12 @@ impl<'a> Parser<'a> { /// Parses a structure field. fn parse_name_and_ty( &mut self, + adt_ty: &str, lo: Span, vis: Visibility, attrs: Vec, ) -> PResult<'a, FieldDef> { - let name = self.parse_field_ident(lo)?; + let name = self.parse_field_ident(adt_ty, lo)?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(FieldDef { @@ -1418,14 +1423,14 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. - fn parse_field_ident(&mut self, lo: Span) -> PResult<'a, Ident> { + fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err()?; if !is_raw && ident.is_reserved() { let err = if self.check_fn_front_matter(false) { let _ = self.parse_fn(&mut Vec::new(), |_| true, lo); let mut err = self.struct_span_err( lo.to(self.prev_token.span), - "functions are not allowed in struct definitions", + &format!("functions are not allowed in {} definitions", adt_ty), ); err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks"); err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); diff --git a/src/test/ui/structs/struct-fn-in-definition.rs b/src/test/ui/structs/struct-fn-in-definition.rs index d841051bdd05..5ae1b727dc77 100644 --- a/src/test/ui/structs/struct-fn-in-definition.rs +++ b/src/test/ui/structs/struct-fn-in-definition.rs @@ -5,10 +5,29 @@ struct S { field: usize, - fn do_something() {} + + fn foo() {} //~^ ERROR functions are not allowed in struct definitions //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information } +union U { + variant: usize, + + fn foo() {} + //~^ ERROR functions are not allowed in union definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + +enum E { + Variant, + + fn foo() {} + //~^ ERROR functions are not allowed in enum definitions + //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks + //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information +} + fn main() {} diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr index 84d7362e024b..1d7cd5272958 100644 --- a/src/test/ui/structs/struct-fn-in-definition.stderr +++ b/src/test/ui/structs/struct-fn-in-definition.stderr @@ -1,11 +1,29 @@ error: functions are not allowed in struct definitions - --> $DIR/struct-fn-in-definition.rs:5:5 + --> $DIR/struct-fn-in-definition.rs:9:5 | -LL | fn do_something() {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() {} + | ^^^^^^^^^^^ | = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information -error: aborting due to previous error +error: functions are not allowed in union definitions + --> $DIR/struct-fn-in-definition.rs:18:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: functions are not allowed in enum definitions + --> $DIR/struct-fn-in-definition.rs:27:5 + | +LL | fn foo() {} + | ^^^^^^^^^^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error: aborting due to 3 previous errors From 6f5ace27290d4142da6d68d8a707d09722e7f3f3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 4 Apr 2021 20:02:32 -0400 Subject: [PATCH 9/9] rustdoc: Link to the docs on namespaces when an unknown disambiguator is found --- src/librustdoc/passes/collect_intra_doc_links.rs | 5 ++++- .../intra-doc/email-address-localhost.stderr | 1 + .../rustdoc-ui/intra-doc/unknown-disambiguator.stderr | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 25b6c187f3b2..4317b9747353 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2017,7 +2017,10 @@ fn disambiguator_error( msg: &str, ) { diag_info.link_range = disambiguator_range; - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |_diag, _sp| {}); + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { + let msg = "see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators"; + diag.note(msg); + }); } /// Report an ambiguity error, where there were multiple possible resolutions. diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr index de215b2163bd..f287f87408c4 100644 --- a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr +++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr @@ -10,6 +10,7 @@ note: the lint level is defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr index 195aaca32a27..94d6d4616518 100644 --- a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -10,36 +10,47 @@ note: the lint level is defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `bar` --> $DIR/unknown-disambiguator.rs:3:35 | LL | //! Linking to [foo@banana] and [`bar@banana!()`]. | ^^^ + | + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `foo` --> $DIR/unknown-disambiguator.rs:9:34 | LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. | ^^^ + | + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `foo` --> $DIR/unknown-disambiguator.rs:9:48 | LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. | ^^^ + | + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `` --> $DIR/unknown-disambiguator.rs:6:31 | LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). | ^ + | + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `` --> $DIR/unknown-disambiguator.rs:6:57 | LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). | ^ + | + = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: aborting due to 6 previous errors