From 3caf0bcdeb9546bd8a3ab58c0e33baabdcaac75a Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 6 Sep 2021 18:12:55 +0200 Subject: [PATCH 01/31] Accept `m!{ .. }.method()` and `m!{ .. }?` statements. --- compiler/rustc_parse/src/parser/stmt.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 068bd36af5524..f1a91c41355ee 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -155,17 +155,20 @@ impl<'a> Parser<'a> { let mac = MacCall { path, args, prior_type_ascription: self.last_type_ascription }; - let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof - { - StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) - } else { - // Since none of the above applied, this is an expression statement macro. - let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); - let e = self.maybe_recover_from_bad_qpath(e, true)?; - let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; - let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; - StmtKind::Expr(e) - }; + let kind = + if (delim == token::Brace && self.token != token::Dot && self.token != token::Question) + || self.token == token::Semi + || self.token == token::Eof + { + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) + } else { + // Since none of the above applied, this is an expression statement macro. + let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); + let e = self.maybe_recover_from_bad_qpath(e, true)?; + let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; + let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; + StmtKind::Expr(e) + }; Ok(self.mk_stmt(lo.to(hi), kind)) } From ebf12529dfa62cf463de4fd5e1355e8ea4fe0559 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 6 Sep 2021 18:17:46 +0200 Subject: [PATCH 02/31] Add test for braced-macro followed by `.` or `?`. --- src/test/ui/parser/macro-braces-dot-question.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/test/ui/parser/macro-braces-dot-question.rs diff --git a/src/test/ui/parser/macro-braces-dot-question.rs b/src/test/ui/parser/macro-braces-dot-question.rs new file mode 100644 index 0000000000000..05de5a845e958 --- /dev/null +++ b/src/test/ui/parser/macro-braces-dot-question.rs @@ -0,0 +1,9 @@ +// check-pass + +use std::io::Write; + +fn main() -> Result<(), std::io::Error> { + vec! { 1, 2, 3 }.len(); + write! { vec![], "" }?; + Ok(()) +} From ce35f8ec56ec7e89d351cd95001f4d819c97e07d Mon Sep 17 00:00:00 2001 From: danakj Date: Thu, 22 Jul 2021 14:52:45 -0400 Subject: [PATCH 03/31] remap-cwd-prefix --- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/config.rs | 15 +++++-- compiler/rustc_session/src/options.rs | 2 + src/doc/rustc/src/command-line-arguments.md | 13 ++++++ .../reproducible-build/Makefile | 42 +++++++++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index afab919bc3c2c..94166715f74f3 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -753,6 +753,7 @@ fn test_debugging_options_tracking_hash() { tracked!(profiler_runtime, "abc".to_string()); tracked!(relax_elf_relocations, Some(true)); tracked!(relro_level, Some(RelroLevel::Full)); + tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); tracked!(report_delayed_bugs, true); tracked!(sanitizer, SanitizerSet::ADDRESS); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fdedb7e6a4afe..32aa035e1cdec 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1920,9 +1920,10 @@ fn parse_extern_dep_specs( fn parse_remap_path_prefix( matches: &getopts::Matches, + debugging_opts: &DebuggingOptions, error_format: ErrorOutputType, ) -> Vec<(PathBuf, PathBuf)> { - matches + let mut mapping: Vec<(PathBuf, PathBuf)> = matches .opt_strs("remap-path-prefix") .into_iter() .map(|remap| match remap.rsplit_once('=') { @@ -1932,7 +1933,15 @@ fn parse_remap_path_prefix( ), Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) - .collect() + .collect(); + match &debugging_opts.remap_cwd_prefix { + Some(to) => match std::env::current_dir() { + Ok(cwd) => mapping.push((cwd, to.clone())), + Err(_) => (), + }, + None => (), + }; + mapping } pub fn build_session_options(matches: &getopts::Matches) -> Options { @@ -2077,7 +2086,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let crate_name = matches.opt_str("crate-name"); - let remap_path_prefix = parse_remap_path_prefix(matches, error_format); + let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format); let pretty = parse_pretty(&debugging_opts, error_format); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9a1be40558ccb..293cf1d0ba365 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1236,6 +1236,8 @@ options! { "whether ELF relocations can be relaxed"), relro_level: Option = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), + remap_cwd_prefix: Option = (None, parse_opt_pathbuf, [TRACKED], + "remap paths under the current working directory to this path prefix"), simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ to rust's source base directory. only meant for testing purposes"), diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7f482f0f2b1a0..f38b4ca744f74 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -345,6 +345,19 @@ replacement is purely textual, with no consideration of the current system's pathname syntax. For example `--remap-path-prefix foo=bar` will match `foo/lib.rs` but not `./foo/lib.rs`. + +## `--remap-cwd-prefix`: remap paths under the cwd in output + +Remap all absolute paths that are rooted under the current working directory to +be under the given value instead. The given value may be absolute or relative, +or empty. This switch takes precidence over `--remap-path-prefix` in case they +would both match a given path. + +This flag allows the command line to be universally reproducible, such that the +same execution will work on all machines, regardless of build environment. + +This is an unstable option. Use `-Z remap-cwd-prefix=val` to specify a value. + ## `--json`: configure json messages printed by the compiler diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile index a17ec212cfd58..762cf5ed2ea71 100644 --- a/src/test/run-make-fulldeps/reproducible-build/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build/Makefile @@ -10,6 +10,9 @@ all: \ link_paths \ remap_paths \ different_source_dirs \ + remap_cwd_bin \ + remap_cwd_rlib \ + remap_cwd_to_empty \ extern_flags smoke: @@ -64,6 +67,45 @@ different_source_dirs: --crate-type rlib) cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1 +remap_cwd_bin: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \ + -Z remap-cwd-prefix=. + cp $(TMPDIR)/reproducible-build $(TMPDIR)/first + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \ + -Z remap-cwd-prefix=.) + cmp "$(TMPDIR)/first" "$(TMPDIR)/reproducible-build" || exit 1 + +remap_cwd_rlib: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=. + cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=.) + cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1 + +remap_cwd_to_empty: + rm -rf $(TMPDIR) && mkdir $(TMPDIR) + $(RUSTC) reproducible-build-aux.rs + mkdir $(TMPDIR)/test + cp reproducible-build.rs $(TMPDIR)/test + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix= + cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib + (cd $(TMPDIR)/test && \ + $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \ + -Z remap-cwd-prefix=) + cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1 + extern_flags: rm -rf $(TMPDIR) && mkdir $(TMPDIR) $(RUSTC) reproducible-build-aux.rs From 2a687deee872917b09519519290521fa8dd472b7 Mon Sep 17 00:00:00 2001 From: danakj Date: Tue, 7 Sep 2021 15:38:29 -0400 Subject: [PATCH 04/31] Move documentation to the unstable book --- src/doc/rustc/src/command-line-arguments.md | 13 ---------- .../src/compiler-flags/remap-cwd-prefix.md | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index f38b4ca744f74..7f482f0f2b1a0 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -345,19 +345,6 @@ replacement is purely textual, with no consideration of the current system's pathname syntax. For example `--remap-path-prefix foo=bar` will match `foo/lib.rs` but not `./foo/lib.rs`. - -## `--remap-cwd-prefix`: remap paths under the cwd in output - -Remap all absolute paths that are rooted under the current working directory to -be under the given value instead. The given value may be absolute or relative, -or empty. This switch takes precidence over `--remap-path-prefix` in case they -would both match a given path. - -This flag allows the command line to be universally reproducible, such that the -same execution will work on all machines, regardless of build environment. - -This is an unstable option. Use `-Z remap-cwd-prefix=val` to specify a value. - ## `--json`: configure json messages printed by the compiler diff --git a/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md new file mode 100644 index 0000000000000..977d258529f8c --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md @@ -0,0 +1,24 @@ +# `remap-cwd-prefix` + +The tracking issue for this feature is: [#87325](https://github.com/rust-lang/rust/issues/87325). + +------------------------ + +This flag will rewrite absolute paths under the current working directory, +replacing the current working directory prefix with a specified value. + +The given value may be absolute or relative, or empty. This switch takes +precidence over `--remap-path-prefix` in case they would both match a given +path. + +This flag helps to produce deterministic output, by removing the current working +directory from build output, while allowing the command line to be universally +reproducible, such that the same execution will work on all machines, regardless +of build environment. + +## Example +```sh +# This would produce an absolute path to main.rs in build outputs of +# "./main.rs". +rustc -Z remap-cwd-prefix=. main.rs +``` From 2691a399762149f2c8dd5c3ffc44244b98c37099 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 13:40:32 -0400 Subject: [PATCH 05/31] Revert "Allow formatting `Anonymous{Struct, Union}` declarations" This reverts commit 64acb7d92135ae722dfce89f0ca9d7cf6576de66. --- src/tools/rustfmt/src/items.rs | 11 +++++-- src/tools/rustfmt/src/lib.rs | 7 +--- src/tools/rustfmt/src/types.rs | 59 ++-------------------------------- 3 files changed, 12 insertions(+), 65 deletions(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 2483d0570d9ea..14041539b9dfd 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -6,7 +6,7 @@ use std::cmp::{max, min, Ordering}; use regex::Regex; use rustc_ast::visit; use rustc_ast::{ast, ptr}; -use rustc_span::{symbol, BytePos, Span}; +use rustc_span::{symbol, BytePos, Span, DUMMY_SP}; use crate::attr::filter_inline_attrs; use crate::comment::{ @@ -31,7 +31,12 @@ use crate::stmt::Stmt; use crate::utils::*; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; -use crate::DEFAULT_VISIBILITY; + +const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility { + kind: ast::VisibilityKind::Inherited, + span: DUMMY_SP, + tokens: None, +}; fn type_annotation_separator(config: &Config) -> &str { colon_spaces(config) @@ -972,7 +977,7 @@ impl<'a> StructParts<'a> { format_header(context, self.prefix, self.ident, self.vis, offset) } - pub(crate) fn from_variant(variant: &'a ast::Variant) -> Self { + fn from_variant(variant: &'a ast::Variant) -> Self { StructParts { prefix: "", ident: variant.ident, diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index 206d2f782909c..47a7b9d4dbe3c 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -32,7 +32,7 @@ use std::path::PathBuf; use std::rc::Rc; use rustc_ast::ast; -use rustc_span::{symbol, DUMMY_SP}; +use rustc_span::symbol; use thiserror::Error; use crate::comment::LineClasses; @@ -96,11 +96,6 @@ mod types; mod vertical; pub(crate) mod visitor; -const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility { - kind: ast::VisibilityKind::Inherited, - span: DUMMY_SP, - tokens: None, -}; /// The various errors that can occur during formatting. Note that not all of /// these can currently be propagated to clients. #[derive(Error, Debug)] diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 640d127e86098..76bf58e875b1f 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1,15 +1,15 @@ use std::iter::ExactSizeIterator; use std::ops::Deref; -use rustc_ast::ast::{self, AttrVec, FnRetTy, Mutability}; -use rustc_span::{symbol::kw, symbol::Ident, BytePos, Pos, Span}; +use rustc_ast::ast::{self, FnRetTy, Mutability}; +use rustc_span::{symbol::kw, BytePos, Pos, Span}; +use crate::comment::{combine_strs_with_missing_comments, contains_comment}; use crate::config::lists::*; use crate::config::{IndentStyle, TypeDensity, Version}; use crate::expr::{ format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType, }; -use crate::items::StructParts; use crate::lists::{ definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, }; @@ -24,11 +24,6 @@ use crate::utils::{ colon_spaces, extra_offset, first_line_width, format_extern, format_mutability, last_line_extendable, last_line_width, mk_sp, rewrite_ident, }; -use crate::DEFAULT_VISIBILITY; -use crate::{ - comment::{combine_strs_with_missing_comments, contains_comment}, - items::format_struct_struct, -}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum PathContext { @@ -769,54 +764,6 @@ impl Rewrite for ast::Ty { ast::TyKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1) } - ast::TyKind::AnonymousStruct(ref fields, recovered) => { - let ident = Ident::new( - kw::Struct, - mk_sp(self.span.lo(), self.span.lo() + BytePos(6)), - ); - let data = ast::VariantData::Struct(fields.clone(), recovered); - let variant = ast::Variant { - attrs: AttrVec::new(), - id: self.id, - span: self.span, - vis: DEFAULT_VISIBILITY, - ident, - data, - disr_expr: None, - is_placeholder: false, - }; - format_struct_struct( - &context, - &StructParts::from_variant(&variant), - fields, - shape.indent, - None, - ) - } - ast::TyKind::AnonymousUnion(ref fields, recovered) => { - let ident = Ident::new( - kw::Union, - mk_sp(self.span.lo(), self.span.lo() + BytePos(5)), - ); - let data = ast::VariantData::Struct(fields.clone(), recovered); - let variant = ast::Variant { - attrs: AttrVec::new(), - id: self.id, - span: self.span, - vis: DEFAULT_VISIBILITY, - ident, - data, - disr_expr: None, - is_placeholder: false, - }; - format_struct_struct( - &context, - &StructParts::from_variant(&variant), - fields, - shape.indent, - None, - ) - } ast::TyKind::Path(ref q_self, ref path) => { rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape) } From 2041fb1a2dc06237ffb63eff8fcfaa93abf67952 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 14:52:43 -0400 Subject: [PATCH 06/31] Revert "Add test for pretty printing anonymous types" This reverts commit d59b1f1ef4be692b67c1ff1b49ec810fd59452cf. --- src/test/pretty/anonymous-types.rs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 src/test/pretty/anonymous-types.rs diff --git a/src/test/pretty/anonymous-types.rs b/src/test/pretty/anonymous-types.rs deleted file mode 100644 index 5ff452e8e43c4..0000000000000 --- a/src/test/pretty/anonymous-types.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Test for issue 85480 -// Pretty print anonymous struct and union types - -// pp-exact -// pretty-compare-only - -struct Foo { - _: union { - _: struct { - a: u8, - b: u16, - }, - c: u32, - }, - d: u64, - e: f32, -} - -type A = - struct { - field: u8, - }; - -fn main() { } From 5560f6d90a6a15fdb52a30f97d28b439b72f6cf3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 14:52:49 -0400 Subject: [PATCH 07/31] Revert "Fix ast expanded printing for anonymous types" This reverts commit 5b4bc05fa57be19bb5962f4b7c0f165e194e3151. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3cf04be160c64..bb00e20d699c1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -986,12 +986,12 @@ impl<'a> State<'a> { self.pclose(); } ast::TyKind::AnonymousStruct(ref fields, ..) => { - self.head("struct"); - self.print_record_struct_body(&fields, ty.span); + self.s.word("struct"); + self.print_record_struct_body(fields, ty.span); } ast::TyKind::AnonymousUnion(ref fields, ..) => { - self.head("union"); - self.print_record_struct_body(&fields, ty.span); + self.s.word("union"); + self.print_record_struct_body(fields, ty.span); } ast::TyKind::Paren(ref typ) => { self.popen(); @@ -1413,7 +1413,12 @@ impl<'a> State<'a> { } } - crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) { + crate fn print_record_struct_body( + &mut self, + fields: &Vec, + span: rustc_span::Span, + ) { + self.nbsp(); self.bopen(); self.hardbreak_if_not_bol(); @@ -1462,7 +1467,6 @@ impl<'a> State<'a> { } ast::VariantData::Struct(ref fields, ..) => { self.print_where_clause(&generics.where_clause); - self.nbsp(); self.print_record_struct_body(fields, span); } } From f38ec9ca34c501b2a618178a14fe2a3c9979ddc9 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 13:41:46 -0400 Subject: [PATCH 08/31] Revert "Add test for restriction of anonymous types on validation" This reverts commit 8a1dd6918bb686a960ad5ced46a16b5b59668464. --- .../ui/unnamed_fields/restrict_anonymous.rs | 52 ------ .../unnamed_fields/restrict_anonymous.stderr | 175 ------------------ 2 files changed, 227 deletions(-) delete mode 100644 src/test/ui/unnamed_fields/restrict_anonymous.rs delete mode 100644 src/test/ui/unnamed_fields/restrict_anonymous.stderr diff --git a/src/test/ui/unnamed_fields/restrict_anonymous.rs b/src/test/ui/unnamed_fields/restrict_anonymous.rs deleted file mode 100644 index 99637d1105301..0000000000000 --- a/src/test/ui/unnamed_fields/restrict_anonymous.rs +++ /dev/null @@ -1,52 +0,0 @@ -#![allow(incomplete_features)] -#![feature(unnamed_fields)] - -fn f() -> struct { field: u8 } {} //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields -//~^ ERROR anonymous structs are unimplemented - -fn f2(a: struct { field: u8 } ) {} //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields -//~^ ERROR anonymous structs are unimplemented - -union G { - field: struct { field: u8 } //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented -} -//~| ERROR unions may not contain fields that need dropping [E0740] - -struct H { _: u8 } // Should error after hir checks - -struct I(struct { field: u8 }, u8); //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields -//~^ ERROR anonymous structs are unimplemented - -enum J { - K(struct { field: u8 }), //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented - L { - _ : struct { field: u8 } //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous fields are not allowed outside of structs or unions - //~| ERROR anonymous structs are unimplemented - }, - M { - _ : u8 //~ ERROR anonymous fields are not allowed outside of structs or unions - } -} - -static M: union { field: u8 } = 0; //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields -//~^ ERROR anonymous unions are unimplemented - -type N = union { field: u8 }; //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields -//~^ ERROR anonymous unions are unimplemented - -fn main() { - const O: struct { field: u8 } = 0; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented - - let p: [struct { field: u8 }; 1]; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented - - let q: (struct { field: u8 }, u8); //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented - - let cl = || -> struct { field: u8 } {}; //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented -} diff --git a/src/test/ui/unnamed_fields/restrict_anonymous.stderr b/src/test/ui/unnamed_fields/restrict_anonymous.stderr deleted file mode 100644 index efcf544fde4dc..0000000000000 --- a/src/test/ui/unnamed_fields/restrict_anonymous.stderr +++ /dev/null @@ -1,175 +0,0 @@ -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:4:11 - | -LL | fn f() -> struct { field: u8 } {} - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:7:10 - | -LL | fn f2(a: struct { field: u8 } ) {} - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:11:12 - | -LL | field: struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:18:10 - | -LL | struct I(struct { field: u8 }, u8); - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:22:7 - | -LL | K(struct { field: u8 }), - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous.rs:25:9 - | -LL | _ : struct { field: u8 } - | -^^^^^^^^^^^^^^^^^^^^^^^ - | | - | anonymous field declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:25:13 - | -LL | _ : struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous.rs:30:9 - | -LL | _ : u8 - | -^^^^^ - | | - | anonymous field declared here - -error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:34:11 - | -LL | static M: union { field: u8 } = 0; - | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here - -error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:37:10 - | -LL | type N = union { field: u8 }; - | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:41:14 - | -LL | const O: struct { field: u8 } = 0; - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:44:13 - | -LL | let p: [struct { field: u8 }; 1]; - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:47:13 - | -LL | let q: (struct { field: u8 }, u8); - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous.rs:50:20 - | -LL | let cl = || -> struct { field: u8 } {}; - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:4:11 - | -LL | fn f() -> struct { field: u8 } {} - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:7:10 - | -LL | fn f2(a: struct { field: u8 } ) {} - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:11:12 - | -LL | field: struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:18:10 - | -LL | struct I(struct { field: u8 }, u8); - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:22:7 - | -LL | K(struct { field: u8 }), - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:25:13 - | -LL | _ : struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous.rs:34:11 - | -LL | static M: union { field: u8 } = 0; - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous.rs:37:10 - | -LL | type N = union { field: u8 }; - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:44:13 - | -LL | let p: [struct { field: u8 }; 1]; - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:47:13 - | -LL | let q: (struct { field: u8 }, u8); - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:50:20 - | -LL | let cl = || -> struct { field: u8 } {}; - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous.rs:41:14 - | -LL | const O: struct { field: u8 } = 0; - | ^^^^^^^^^^^^^^^^^^^^ - -error[E0740]: unions may not contain fields that need dropping - --> $DIR/restrict_anonymous.rs:11:5 - | -LL | field: struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/restrict_anonymous.rs:11:5 - | -LL | field: struct { field: u8 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 27 previous errors - -For more information about this error, try `rustc --explain E0740`. From b6aa7e3105a76d1dcb0c4d0e475657056a3885c5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 13:48:42 -0400 Subject: [PATCH 09/31] Manually crafted revert of d4ad050ce5778a09566f6f9ec172565815d54604 . --- .../rustc_ast_passes/src/ast_validation.rs | 68 ------------------- 1 file changed, 68 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index aca4503903c06..07f721d2d840a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -193,11 +193,6 @@ impl<'a> AstValidator<'a> { } } } - TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => { - self.with_banned_assoc_ty_bound(|this| { - walk_list!(this, visit_struct_field_def, fields) - }); - } _ => visit::walk_ty(self, t), } } @@ -205,7 +200,6 @@ impl<'a> AstValidator<'a> { fn visit_struct_field_def(&mut self, field: &'a FieldDef) { if let Some(ident) = field.ident { if ident.name == kw::Underscore { - self.check_anonymous_field(field); self.visit_vis(&field.vis); self.visit_ident(ident); self.visit_ty_common(&field.ty); @@ -251,66 +245,6 @@ impl<'a> AstValidator<'a> { err.emit(); } - fn check_anonymous_field(&self, field: &FieldDef) { - let FieldDef { ty, .. } = field; - match &ty.kind { - TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => { - // We already checked for `kw::Underscore` before calling this function, - // so skip the check - } - TyKind::Path(..) => { - // If the anonymous field contains a Path as type, we can't determine - // if the path is a valid struct or union, so skip the check - } - _ => { - let msg = "unnamed fields can only have struct or union types"; - let label = "not a struct or union"; - self.err_handler() - .struct_span_err(field.span, msg) - .span_label(ty.span, label) - .emit(); - } - } - } - - fn deny_anonymous_struct(&self, ty: &Ty) { - match &ty.kind { - TyKind::AnonymousStruct(..) => { - self.err_handler() - .struct_span_err( - ty.span, - "anonymous structs are not allowed outside of unnamed struct or union fields", - ) - .span_label(ty.span, "anonymous struct declared here") - .emit(); - } - TyKind::AnonymousUnion(..) => { - self.err_handler() - .struct_span_err( - ty.span, - "anonymous unions are not allowed outside of unnamed struct or union fields", - ) - .span_label(ty.span, "anonymous union declared here") - .emit(); - } - _ => {} - } - } - - fn deny_anonymous_field(&self, field: &FieldDef) { - if let Some(ident) = field.ident { - if ident.name == kw::Underscore { - self.err_handler() - .struct_span_err( - field.span, - "anonymous fields are not allowed outside of structs or unions", - ) - .span_label(ident.span, "anonymous field declared here") - .emit() - } - } - } - fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { @@ -1067,7 +1001,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_ty(&mut self, ty: &'a Ty) { self.visit_ty_common(ty); - self.deny_anonymous_struct(ty); self.walk_ty(ty) } @@ -1082,7 +1015,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_field_def(&mut self, s: &'a FieldDef) { - self.deny_anonymous_field(s); visit::walk_field_def(self, s) } From 91feb76d133952825e3eb32bed399ec6e4bd9219 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 14:03:40 -0400 Subject: [PATCH 10/31] Revert "Implement Anonymous{Struct, Union} in the AST" This reverts commit 059b68dd677808e14e560802d235ad40beeba71e. Note that this was manually adjusted to retain some of the refactoring introduced by commit 059b68dd677808e14e560802d235ad40beeba71e, so that it could likewise retain the correction introduced in commit 5b4bc05fa57be19bb5962f4b7c0f165e194e3151 --- compiler/rustc_ast/src/ast.rs | 4 - compiler/rustc_ast/src/mut_visit.rs | 3 - compiler/rustc_ast/src/visit.rs | 3 - compiler/rustc_ast_lowering/src/item.rs | 5 +- compiler/rustc_ast_lowering/src/lib.rs | 9 -- compiler/rustc_ast_passes/src/feature_gate.rs | 1 - compiler/rustc_ast_pretty/src/pprust/state.rs | 8 -- compiler/rustc_feature/src/active.rs | 3 - compiler/rustc_parse/src/parser/item.rs | 35 ++---- compiler/rustc_parse/src/parser/ty.rs | 13 -- compiler/rustc_span/src/symbol.rs | 1 - .../feature-gate-unnamed_fields.rs | 27 ----- .../feature-gate-unnamed_fields.stderr | 111 ------------------ 13 files changed, 14 insertions(+), 209 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-unnamed_fields.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b92c5fa072786..c27ab810a4c60 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1902,10 +1902,6 @@ pub enum TyKind { Never, /// A tuple (`(A, B, C, D,...)`). Tup(Vec>), - /// An anonymous struct type i.e. `struct { foo: Type }` - AnonymousStruct(Vec, bool), - /// An anonymous union type i.e. `union { bar: Type }` - AnonymousUnion(Vec, bool), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., ` as SomeTrait>::SomeType`. /// diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 2ec941cbb2466..ba86036577ac5 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -484,9 +484,6 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } TyKind::MacCall(mac) => vis.visit_mac_call(mac), - TyKind::AnonymousStruct(fields, ..) | TyKind::AnonymousUnion(fields, ..) => { - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } } vis.visit_span(span); visit_lazy_tts(tokens, vis); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c30f711b39707..b38031042e0f0 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -407,9 +407,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac), - TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => { - walk_list!(visitor, visit_field_def, fields) - } TyKind::Never | TyKind::CVarArgs => {} } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b7497c713f3df..a77e3e1997fd6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -748,10 +748,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_field_def( - &mut self, - (index, f): (usize, &FieldDef), - ) -> hir::FieldDef<'hir> { + fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> { let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind { let t = self.lower_path_ty( &f.ty, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fa14764c42a73..6a387d62c90c4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1289,15 +1289,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => hir::TyKind::Err, - // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS - TyKind::AnonymousStruct(ref _fields, _recovered) => { - self.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit(); - hir::TyKind::Err - } - TyKind::AnonymousUnion(ref _fields, _recovered) => { - self.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit(); - hir::TyKind::Err - } TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 1defb65ed8793..30bc4edd7e69c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -668,7 +668,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { // involved, so we only emit errors where there are no other parsing errors. gate_all!(destructuring_assignment, "destructuring assignments are unstable"); } - gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index bb00e20d699c1..c24882086e12d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -985,14 +985,6 @@ impl<'a> State<'a> { } self.pclose(); } - ast::TyKind::AnonymousStruct(ref fields, ..) => { - self.s.word("struct"); - self.print_record_struct_body(fields, ty.span); - } - ast::TyKind::AnonymousUnion(ref fields, ..) => { - self.s.word("union"); - self.print_record_struct_body(fields, ty.span); - } ast::TyKind::Paren(ref typ) => { self.popen(); self.print_type(typ); diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index a3807a2bb9fde..d409746584274 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -639,9 +639,6 @@ declare_features! ( /// Allows specifying the as-needed link modifier (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), - /// Allows unnamed fields of struct and union type - (incomplete, unnamed_fields, "1.53.0", Some(49804), None), - /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. (active, more_qualified_paths, "1.54.0", Some(86935), None), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 10c73fd64bc19..29e20f2747f1b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1234,7 +1234,7 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Union(vdata, generics))) } - pub(super) fn parse_record_struct_body( + fn parse_record_struct_body( &mut self, adt_ty: &str, ) -> PResult<'a, (Vec, /* recovered */ bool)> { @@ -1468,28 +1468,19 @@ impl<'a> Parser<'a> { 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() { - if ident.name == kw::Underscore { - self.sess.gated_spans.gate(sym::unnamed_fields, lo); + 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), + &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"); + err } else { - let err = if self.check_fn_front_matter(false) { - // We use `parse_fn` to get a span for the function - if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) { - db.delay_as_bug(); - } - let mut err = self.struct_span_err( - lo.to(self.prev_token.span), - &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"); - err - } else { - self.expected_ident_found() - }; - return Err(err); - } + self.expected_ident_found() + }; + return Err(err); } self.bump(); Ok(ident) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 299fc916ac97f..98400372c36a6 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -226,19 +226,6 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(kw::Impl) { self.parse_impl_ty(&mut impl_dyn_multi)? - } else if self.token.is_keyword(kw::Union) - && self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) - { - self.bump(); - let (fields, recovered) = self.parse_record_struct_body("union")?; - let span = lo.to(self.prev_token.span); - self.sess.gated_spans.gate(sym::unnamed_fields, span); - TyKind::AnonymousUnion(fields, recovered) - } else if self.eat_keyword(kw::Struct) { - let (fields, recovered) = self.parse_record_struct_body("struct")?; - let span = lo.to(self.prev_token.span); - self.sess.gated_spans.gate(sym::unnamed_fields, span); - TyKind::AnonymousStruct(fields, recovered) } else if self.is_explicit_dyn_type() { self.parse_dyn_ty(&mut impl_dyn_multi)? } else if self.eat_lt() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 24023163cc30e..675c5108720bb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1358,7 +1358,6 @@ symbols! { unix, unlikely, unmarked_api, - unnamed_fields, unpin, unreachable, unreachable_code, diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs b/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs deleted file mode 100644 index bd815dbcc9242..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs +++ /dev/null @@ -1,27 +0,0 @@ -struct Foo { - foo: u8, - _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658] - //~^ ERROR unnamed fields are not yet fully implemented [E0658] - //~| ERROR anonymous unions are unimplemented - bar: u8, - baz: u16 - } -} - -union Bar { - foobar: u8, - _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658] - //~^ ERROR unnamed fields are not yet fully implemented [E0658] - //~| ERROR anonymous structs are unimplemented - //~| ERROR unions may not contain fields that need dropping [E0740] - foobaz: u8, - barbaz: u16 - } -} - -struct S; -struct Baz { - _: S //~ ERROR unnamed fields are not yet fully implemented [E0658] -} - -fn main(){} diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr b/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr deleted file mode 100644 index 4f3ab85c98792..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr +++ /dev/null @@ -1,111 +0,0 @@ -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:3:5 - | -LL | _: union { - | ^ - | - = note: see issue #49804 for more information - = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable - -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:3:8 - | -LL | _: union { - | ________^ -LL | | -LL | | -LL | | bar: u8, -LL | | baz: u16 -LL | | } - | |_____^ - | - = note: see issue #49804 for more information - = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable - -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:13:5 - | -LL | _: struct { - | ^ - | - = note: see issue #49804 for more information - = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable - -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:13:8 - | -LL | _: struct { - | ________^ -LL | | -LL | | -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - | - = note: see issue #49804 for more information - = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable - -error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:24:5 - | -LL | _: S - | ^ - | - = note: see issue #49804 for more information - = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable - -error: anonymous unions are unimplemented - --> $DIR/feature-gate-unnamed_fields.rs:3:8 - | -LL | _: union { - | ________^ -LL | | -LL | | -LL | | bar: u8, -LL | | baz: u16 -LL | | } - | |_____^ - -error: anonymous structs are unimplemented - --> $DIR/feature-gate-unnamed_fields.rs:13:8 - | -LL | _: struct { - | ________^ -LL | | -LL | | -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - -error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-unnamed_fields.rs:13:5 - | -LL | / _: struct { -LL | | -LL | | -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - | -note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-unnamed_fields.rs:13:5 - | -LL | / _: struct { -LL | | -LL | | -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - -error: aborting due to 8 previous errors - -Some errors have detailed explanations: E0658, E0740. -For more information about an error, try `rustc --explain E0658`. From f26f1ed9a7208c0d928f0413cdd5f0966fa2c399 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Sep 2021 14:48:12 -0400 Subject: [PATCH 11/31] Re-add 71a7f8f1884b2c83eeb4a545eef16df1f2ea6476 post-revert. --- compiler/rustc_parse/src/parser/item.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 29e20f2747f1b..c5b961f12b2ab 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1469,7 +1469,10 @@ impl<'a> Parser<'a> { 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); + // We use `parse_fn` to get a span for the function + if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) { + db.delay_as_bug(); + } let mut err = self.struct_span_err( lo.to(self.prev_token.span), &format!("functions are not allowed in {} definitions", adt_ty), From 35370a7ba3d52bfe2a6121a0eaccbc240ed9559d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 9 Sep 2021 09:31:56 -0400 Subject: [PATCH 12/31] regression test for issue #88583. --- src/test/ui/parser/issue-88583-union-as-ident.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/ui/parser/issue-88583-union-as-ident.rs diff --git a/src/test/ui/parser/issue-88583-union-as-ident.rs b/src/test/ui/parser/issue-88583-union-as-ident.rs new file mode 100644 index 0000000000000..b3d66d46b1d4b --- /dev/null +++ b/src/test/ui/parser/issue-88583-union-as-ident.rs @@ -0,0 +1,15 @@ +// check-pass + +#![allow(non_camel_case_types)] + +struct union; + +impl union { + pub fn new() -> Self { + union { } + } +} + +fn main() { + let _u = union::new(); +} From 2052839b7db0406634a518b0b9df1d24facbc506 Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Mon, 6 Sep 2021 03:35:37 -0400 Subject: [PATCH 13/31] Fix ICE when `start` lang item has wrong generics --- compiler/rustc_hir/src/lang_items.rs | 2 +- .../run-make-fulldeps/target-specs/foo.rs | 2 +- .../lang-item-generic-requirements.rs | 16 ++++++++++--- .../lang-item-generic-requirements.stderr | 23 +++++++++++++------ 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b85ed0cb4bbe5..9e323c3e93c70 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -299,7 +299,7 @@ language_item_table! { Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; - Start, sym::start, start_fn, Target::Fn, GenericRequirement::None; + Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None; diff --git a/src/test/run-make-fulldeps/target-specs/foo.rs b/src/test/run-make-fulldeps/target-specs/foo.rs index 9ff33e24d04d7..83fdc452a3b13 100644 --- a/src/test/run-make-fulldeps/target-specs/foo.rs +++ b/src/test/run-make-fulldeps/target-specs/foo.rs @@ -11,7 +11,7 @@ trait Sized {} auto trait Freeze {} #[lang = "start"] -fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { +fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/src/test/ui/lang-items/lang-item-generic-requirements.rs b/src/test/ui/lang-items/lang-item-generic-requirements.rs index d785749afc9c2..c0b958f2bf221 100644 --- a/src/test/ui/lang-items/lang-item-generic-requirements.rs +++ b/src/test/ui/lang-items/lang-item-generic-requirements.rs @@ -1,9 +1,8 @@ -// Checks whether declaring a lang item with the wrong number -// of generic arguments crashes the compiler (issue #83893, #87573, and part of #9307). +// Checks that declaring a lang item with the wrong number +// of generic arguments errors rather than crashing (issue #83893, #87573, part of #9307, #79559). #![feature(lang_items, no_core)] #![no_core] -#![crate_type = "lib"] #[lang = "sized"] trait MySized {} @@ -26,6 +25,14 @@ struct MyPhantomData; //~^ ERROR parameter `T` is never used //~| ERROR parameter `U` is never used +// When the `start` lang item is missing generics very odd things can happen, especially when +// it comes to cross-crate monomorphization +#[lang = "start"] +//~^ ERROR `start` language item must be applied to a function with 1 generic argument [E0718] +fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + 0 +} + fn ice() { // Use add let r = 5; @@ -42,3 +49,6 @@ fn ice() { // Use phantomdata let _ = MyPhantomData::<(), i32>; } + +// use `start` +fn main() {} diff --git a/src/test/ui/lang-items/lang-item-generic-requirements.stderr b/src/test/ui/lang-items/lang-item-generic-requirements.stderr index add5938811c28..df5a77850f14d 100644 --- a/src/test/ui/lang-items/lang-item-generic-requirements.stderr +++ b/src/test/ui/lang-items/lang-item-generic-requirements.stderr @@ -1,5 +1,5 @@ error[E0718]: `add` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:11:1 + --> $DIR/lang-item-generic-requirements.rs:10:1 | LL | #[lang = "add"] | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | trait MyAdd<'a, T> {} | ------- this trait has 2 generic arguments error[E0718]: `drop_in_place` language item must be applied to a function with at least 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:15:1 + --> $DIR/lang-item-generic-requirements.rs:14:1 | LL | #[lang = "drop_in_place"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn my_ptr_drop() {} | - this function has 0 generic arguments error[E0718]: `index` language item must be applied to a trait with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:19:1 + --> $DIR/lang-item-generic-requirements.rs:18:1 | LL | #[lang = "index"] | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | trait MyIndex<'a, T> {} | ------- this trait has 2 generic arguments error[E0718]: `phantom_data` language item must be applied to a struct with 1 generic argument - --> $DIR/lang-item-generic-requirements.rs:23:1 + --> $DIR/lang-item-generic-requirements.rs:22:1 | LL | #[lang = "phantom_data"] | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,8 +32,17 @@ LL | LL | struct MyPhantomData; | ------ this struct has 2 generic arguments +error[E0718]: `start` language item must be applied to a function with 1 generic argument + --> $DIR/lang-item-generic-requirements.rs:30:1 + | +LL | #[lang = "start"] + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize { + | - this function has 0 generic arguments + error[E0392]: parameter `T` is never used - --> $DIR/lang-item-generic-requirements.rs:25:22 + --> $DIR/lang-item-generic-requirements.rs:24:22 | LL | struct MyPhantomData; | ^ unused parameter @@ -42,7 +51,7 @@ LL | struct MyPhantomData; = help: if you intended `T` to be a const parameter, use `const T: usize` instead error[E0392]: parameter `U` is never used - --> $DIR/lang-item-generic-requirements.rs:25:25 + --> $DIR/lang-item-generic-requirements.rs:24:25 | LL | struct MyPhantomData; | ^ unused parameter @@ -50,7 +59,7 @@ LL | struct MyPhantomData; = help: consider removing `U` or referring to it in a field = help: if you intended `U` to be a const parameter, use `const U: usize` instead -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0392, E0718. For more information about an error, try `rustc --explain E0392`. From 8be3e26dd91f71449672724f2efe7f90cc85e97e Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Fri, 10 Sep 2021 09:33:06 -0400 Subject: [PATCH 14/31] update test --- src/test/run-make-fulldeps/target-specs/foo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make-fulldeps/target-specs/foo.rs b/src/test/run-make-fulldeps/target-specs/foo.rs index 83fdc452a3b13..d576a1dd28192 100644 --- a/src/test/run-make-fulldeps/target-specs/foo.rs +++ b/src/test/run-make-fulldeps/target-specs/foo.rs @@ -11,7 +11,7 @@ trait Sized {} auto trait Freeze {} #[lang = "start"] -fn start(_main: *const u8, _argc: isize, _argv: *const *const u8) -> isize { +fn start(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize { 0 } From 5dab3c5cf5383b1866b374d74305196b72a0b593 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 10 Sep 2021 18:16:58 -0700 Subject: [PATCH 15/31] feat(rustc_typeck): suggest removing bad parens in `(recv.method)()` Fixes #88803 --- compiler/rustc_typeck/src/check/expr.rs | 18 +++++++++++++++++- .../ui/typeck/issue-88803-call-expr-method.rs | 7 +++++++ .../typeck/issue-88803-call-expr-method.stderr | 12 ++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/typeck/issue-88803-call-expr-method.rs create mode 100644 src/test/ui/typeck/issue-88803-call-expr-method.stderr diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index d578fac4cdb22..8513659344018 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1842,7 +1842,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_t ); err.span_label(field.span, "method, not a field"); - if !self.expr_in_place(expr.hir_id) { + let expr_is_call = if let hir::Node::Expr(parent_expr) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id)) + { + matches!(parent_expr.kind, ExprKind::Call(..)) + } else { + false + }; + let expr_snippet = + self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); + if expr_is_call && expr_snippet.starts_with("(") && expr_snippet.ends_with(")") { + err.span_suggestion_short( + expr.span, + "remove wrapping parentheses to call the method", + expr_snippet[1..expr_snippet.len() - 1].to_owned(), + Applicability::MachineApplicable, + ); + } else if !self.expr_in_place(expr.hir_id) { self.suggest_method_call( &mut err, "use parentheses to call the method", diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.rs b/src/test/ui/typeck/issue-88803-call-expr-method.rs new file mode 100644 index 0000000000000..fba233eec9b00 --- /dev/null +++ b/src/test/ui/typeck/issue-88803-call-expr-method.rs @@ -0,0 +1,7 @@ +fn main() { + let a = Some(42); + println!( + "The value is {}.", + (a.unwrap)() //~ERROR [E0615] + ); +} diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.stderr b/src/test/ui/typeck/issue-88803-call-expr-method.stderr new file mode 100644 index 0000000000000..9383848db941f --- /dev/null +++ b/src/test/ui/typeck/issue-88803-call-expr-method.stderr @@ -0,0 +1,12 @@ +error[E0615]: attempted to take value of method `unwrap` on type `Option<{integer}>` + --> $DIR/issue-88803-call-expr-method.rs:5:12 + | +LL | (a.unwrap)() + | ---^^^^^^- + | | | + | | method, not a field + | help: remove wrapping parentheses to call the method + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0615`. From e5c2412e52019ef35f9c6b3524cd5caf972e26b7 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 10 Sep 2021 18:34:51 -0700 Subject: [PATCH 16/31] Add the corrections stuff to the 88803 test case --- src/test/ui/typeck/issue-88803-call-expr-method.fixed | 9 +++++++++ src/test/ui/typeck/issue-88803-call-expr-method.rs | 2 ++ src/test/ui/typeck/issue-88803-call-expr-method.stderr | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/typeck/issue-88803-call-expr-method.fixed diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.fixed b/src/test/ui/typeck/issue-88803-call-expr-method.fixed new file mode 100644 index 0000000000000..19b96ecf3fc3a --- /dev/null +++ b/src/test/ui/typeck/issue-88803-call-expr-method.fixed @@ -0,0 +1,9 @@ +// run-rustfix + +fn main() { + let a = Some(42); + println!( + "The value is {}.", + a.unwrap() //~ERROR [E0615] + ); +} diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.rs b/src/test/ui/typeck/issue-88803-call-expr-method.rs index fba233eec9b00..a061994663749 100644 --- a/src/test/ui/typeck/issue-88803-call-expr-method.rs +++ b/src/test/ui/typeck/issue-88803-call-expr-method.rs @@ -1,3 +1,5 @@ +// run-rustfix + fn main() { let a = Some(42); println!( diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.stderr b/src/test/ui/typeck/issue-88803-call-expr-method.stderr index 9383848db941f..4b7ea95dee2a7 100644 --- a/src/test/ui/typeck/issue-88803-call-expr-method.stderr +++ b/src/test/ui/typeck/issue-88803-call-expr-method.stderr @@ -1,5 +1,5 @@ error[E0615]: attempted to take value of method `unwrap` on type `Option<{integer}>` - --> $DIR/issue-88803-call-expr-method.rs:5:12 + --> $DIR/issue-88803-call-expr-method.rs:7:12 | LL | (a.unwrap)() | ---^^^^^^- From d98892b67f9b1f04c8c3c90cd99cd24738fd30ba Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 10 Sep 2021 18:48:25 -0700 Subject: [PATCH 17/31] Make sure the call span parens check only fires on the callee, not args --- compiler/rustc_typeck/src/check/expr.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8513659344018..61d5b6985f1bf 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1842,13 +1842,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_t ); err.span_label(field.span, "method, not a field"); - let expr_is_call = if let hir::Node::Expr(parent_expr) = - self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id)) - { - matches!(parent_expr.kind, ExprKind::Call(..)) - } else { - false - }; + let expr_is_call = + if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id)) + { + expr.hir_id == callee.hir_id + } else { + false + }; let expr_snippet = self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); if expr_is_call && expr_snippet.starts_with("(") && expr_snippet.ends_with(")") { From 8be729cdd6473859f4fb54aaf74dce56f0775ef1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 12 Sep 2021 19:51:09 -0700 Subject: [PATCH 18/31] chore: convert to a multi-part suggestion --- compiler/rustc_typeck/src/check/expr.rs | 10 +++++++--- .../ui/typeck/issue-88803-call-expr-method.stderr | 11 +++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 61d5b6985f1bf..f4e3c8e0d9f7f 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1853,10 +1853,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_snippet = self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap_or(String::new()); if expr_is_call && expr_snippet.starts_with("(") && expr_snippet.ends_with(")") { - err.span_suggestion_short( - expr.span, + let after_open = expr.span.lo() + rustc_span::BytePos(1); + let before_close = expr.span.hi() - rustc_span::BytePos(1); + err.multipart_suggestion( "remove wrapping parentheses to call the method", - expr_snippet[1..expr_snippet.len() - 1].to_owned(), + vec![ + (expr.span.with_hi(after_open), String::new()), + (expr.span.with_lo(before_close), String::new()), + ], Applicability::MachineApplicable, ); } else if !self.expr_in_place(expr.hir_id) { diff --git a/src/test/ui/typeck/issue-88803-call-expr-method.stderr b/src/test/ui/typeck/issue-88803-call-expr-method.stderr index 4b7ea95dee2a7..dd717ed9416d3 100644 --- a/src/test/ui/typeck/issue-88803-call-expr-method.stderr +++ b/src/test/ui/typeck/issue-88803-call-expr-method.stderr @@ -2,10 +2,13 @@ error[E0615]: attempted to take value of method `unwrap` on type `Option<{intege --> $DIR/issue-88803-call-expr-method.rs:7:12 | LL | (a.unwrap)() - | ---^^^^^^- - | | | - | | method, not a field - | help: remove wrapping parentheses to call the method + | ^^^^^^ method, not a field + | +help: remove wrapping parentheses to call the method + | +LL - (a.unwrap)() +LL + a.unwrap() + | error: aborting due to previous error From 7d8d7a03412f6db1402f2713ee96a2040cfb24d2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 13 Sep 2021 17:50:59 +0200 Subject: [PATCH 19/31] Add negative test in macro-braces-dot-question.rs. --- src/test/ui/parser/macro-braces-dot-question.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/ui/parser/macro-braces-dot-question.rs b/src/test/ui/parser/macro-braces-dot-question.rs index 05de5a845e958..016b434a6124a 100644 --- a/src/test/ui/parser/macro-braces-dot-question.rs +++ b/src/test/ui/parser/macro-braces-dot-question.rs @@ -5,5 +5,7 @@ use std::io::Write; fn main() -> Result<(), std::io::Error> { vec! { 1, 2, 3 }.len(); write! { vec![], "" }?; + println!{""} + [0]; // separate statement, not indexing into the result of println. Ok(()) } From 1053a5bb0ff9f781cc1fa0385ce699fe49ee2ad2 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Mon, 13 Sep 2021 12:39:45 -0700 Subject: [PATCH 20/31] `Wrapping` has the same layout and ABI as `T` --- library/core/src/num/wrapping.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index be6d70320d407..b078cdf5479d7 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -32,6 +32,10 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; /// /// assert_eq!(u32::MAX, (zero - one).0); /// ``` +/// +/// # Layout +/// +/// `Wrapping` is guaranteed to have the same layout and ABI as `T`. #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] From ae2cda6cac27088e67c08665189beebae75e9d3b Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Sun, 29 Aug 2021 08:34:23 +0000 Subject: [PATCH 21/31] Tokenize emoji as if they were valid indentifiers In the lexer, consider emojis to be valid identifiers and reject them later to avoid knock down parse errors. --- Cargo.lock | 42 ++++++++++++ compiler/rustc_interface/src/passes.rs | 12 +++- compiler/rustc_lexer/Cargo.toml | 1 + compiler/rustc_lexer/src/lib.rs | 25 +++++++ compiler/rustc_parse/src/lexer/mod.rs | 6 ++ compiler/rustc_session/src/parse.rs | 8 ++- src/test/ui/parser/emoji-identifiers.rs | 16 +++++ src/test/ui/parser/emoji-identifiers.stderr | 72 +++++++++++++++++++++ 8 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/parser/emoji-identifiers.rs create mode 100644 src/test/ui/parser/emoji-identifiers.stderr diff --git a/Cargo.lock b/Cargo.lock index 80acf227698e9..ca3f44da79663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4003,6 +4003,7 @@ name = "rustc_lexer" version = "0.1.0" dependencies = [ "expect-test", + "unic-emoji-char", "unicode-xid", ] @@ -5466,6 +5467,47 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-emoji-char" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.6.0" diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 1f3d6f70ff837..f631b46e565d2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -35,7 +35,7 @@ use rustc_session::output::{filename_for_input, filename_for_metadata}; use rustc_session::search_paths::PathKind; use rustc_session::Session; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::FileName; +use rustc_span::{FileName, MultiSpan}; use rustc_trait_selection::traits; use rustc_typeck as typeck; use tempfile::Builder as TempFileBuilder; @@ -445,6 +445,16 @@ pub fn configure_and_expand( } }); + // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. + sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| { + for (ident, spans) in identifiers.drain() { + sess.diagnostic().span_err( + MultiSpan::from(spans), + &format!("identifiers cannot contain emojis: `{}`", ident), + ); + } + }); + Ok(krate) } diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 7e05fe545cabe..a43333339543e 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -17,6 +17,7 @@ doctest = false # Note that this crate purposefully does not depend on other rustc crates [dependencies] unicode-xid = "0.2.0" +unic-emoji-char = "0.9.0" [dev-dependencies] expect-test = "1.0" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b64a891cb2526..a729c0c0bbea3 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -64,6 +64,8 @@ pub enum TokenKind { /// "ident" or "continue" /// At this step keywords are also considered identifiers. Ident, + /// Like the above, but containing invalid unicode codepoints. + InvalidIdent, /// "r#ident" RawIdent, /// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the @@ -411,6 +413,11 @@ impl Cursor<'_> { let kind = Str { terminated }; Literal { kind, suffix_start } } + // Identifier (this should be checked after other variant that can + // start as identifier). + c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => { + self.fake_ident_or_unknown_prefix() + } _ => Unknown, }; Token::new(token_kind, self.len_consumed()) @@ -492,10 +499,28 @@ impl Cursor<'_> { // we see a prefix here, it is definitely an unknown prefix. match self.first() { '#' | '"' | '\'' => UnknownPrefix, + c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => { + self.fake_ident_or_unknown_prefix() + } _ => Ident, } } + fn fake_ident_or_unknown_prefix(&mut self) -> TokenKind { + // Start is already eaten, eat the rest of identifier. + self.eat_while(|c| { + unicode_xid::UnicodeXID::is_xid_continue(c) + || (!c.is_ascii() && unic_emoji_char::is_emoji(c)) + || c == '\u{200d}' + }); + // Known prefixes must have been handled earlier. So if + // we see a prefix here, it is definitely an unknown prefix. + match self.first() { + '#' | '"' | '\'' => UnknownPrefix, + _ => InvalidIdent, + } + } + fn number(&mut self, first_digit: char) -> LiteralKind { debug_assert!('0' <= self.prev() && self.prev() <= '9'); let mut base = Base::Decimal; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1e65cc27154a8..46501fc2e5956 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -191,6 +191,12 @@ impl<'a> StringReader<'a> { } token::Ident(sym, is_raw_ident) } + rustc_lexer::TokenKind::InvalidIdent => { + let sym = nfc_normalize(self.str_from(start)); + let span = self.mk_sp(start, self.pos); + self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span); + token::Ident(sym, false) + } rustc_lexer::TokenKind::Literal { kind, suffix_start } => { let suffix_start = start + BytePos(suffix_start as u32); let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index a007b53030271..69d02e6c1ae93 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -119,8 +119,13 @@ pub struct ParseSess { pub config: CrateConfig, pub edition: Edition, pub missing_fragment_specifiers: Lock>, - /// Places where raw identifiers were used. This is used for feature-gating raw identifiers. + /// Places where raw identifiers were used. This is used to avoid complaining about idents + /// clashing with keywords in new editions. pub raw_identifier_spans: Lock>, + /// Places where identifiers that contain invalid Unicode codepoints but that look like they + /// should be. Useful to avoid bad tokenization when encountering emojis. We group them to + /// provide a single error per unique incorrect identifier. + pub bad_unicode_identifiers: Lock>>, source_map: Lrc, pub buffered_lints: Lock>, /// Contains the spans of block expressions that could have been incomplete based on the @@ -160,6 +165,7 @@ impl ParseSess { edition: ExpnId::root().expn_data().edition, missing_fragment_specifiers: Default::default(), raw_identifier_spans: Lock::new(Vec::new()), + bad_unicode_identifiers: Lock::new(Default::default()), source_map, buffered_lints: Lock::new(vec![]), ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs new file mode 100644 index 0000000000000..2f4df4cf21619 --- /dev/null +++ b/src/test/ui/parser/emoji-identifiers.rs @@ -0,0 +1,16 @@ +struct ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily; //~ ERROR identifiers cannot contain emojis +struct ๐Ÿ‘€; //~ ERROR identifiers cannot contain emojis +impl ๐Ÿ‘€ { + fn full_of_โœจ() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emojis + ๐Ÿ‘€ + } +} +fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emojis + ๐Ÿ‘€::full_ofโœจ() //~ ERROR no function or associated item named `full_ofโœจ` found for struct `๐Ÿ‘€` + //~^ ERROR identifiers cannot contain emojis +} +fn main() { + let _ = i_like_to_๐Ÿ˜„_a_lot(); //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope + //~^ ERROR identifiers cannot contain emojis +} + diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr new file mode 100644 index 0000000000000..3b17bb01de953 --- /dev/null +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -0,0 +1,72 @@ +error[E0425]: cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope + --> $DIR/emoji-identifiers.rs:13:13 + | +LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { + | ----------------------------- similarly named function `i_like_to_๐Ÿ˜…_a_lot` defined here +... +LL | let _ = i_like_to_๐Ÿ˜„_a_lot(); + | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_๐Ÿ˜…_a_lot` + +error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜„_a_lot` + --> $DIR/emoji-identifiers.rs:13:13 + | +LL | let _ = i_like_to_๐Ÿ˜„_a_lot(); + | ^^^^^^^^^^^^^^^^^^ + +error: identifiers cannot contain emojis: `full_of_โœจ` + --> $DIR/emoji-identifiers.rs:4:8 + | +LL | fn full_of_โœจ() -> ๐Ÿ‘€ { + | ^^^^^^^^^^ + +error: identifiers cannot contain emojis: `full_ofโœจ` + --> $DIR/emoji-identifiers.rs:9:8 + | +LL | ๐Ÿ‘€::full_ofโœจ() + | ^^^^^^^^^ + +error: identifiers cannot contain emojis: `๐Ÿ‘€` + --> $DIR/emoji-identifiers.rs:2:8 + | +LL | struct ๐Ÿ‘€; + | ^^ +LL | impl ๐Ÿ‘€ { + | ^^ +LL | fn full_of_โœจ() -> ๐Ÿ‘€ { + | ^^ +LL | ๐Ÿ‘€ + | ^^ +... +LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { + | ^^ +LL | ๐Ÿ‘€::full_ofโœจ() + | ^^ + +error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜…_a_lot` + --> $DIR/emoji-identifiers.rs:8:4 + | +LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { + | ^^^^^^^^^^^^^^^^^^ + +error: identifiers cannot contain emojis: `ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily` + --> $DIR/emoji-identifiers.rs:1:8 + | +LL | struct ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily; + | ^^^^^^^^^^^^^^^^^^ + +error[E0599]: no function or associated item named `full_ofโœจ` found for struct `๐Ÿ‘€` in the current scope + --> $DIR/emoji-identifiers.rs:9:8 + | +LL | struct ๐Ÿ‘€; + | ---------- function or associated item `full_ofโœจ` not found for this +... +LL | ๐Ÿ‘€::full_ofโœจ() + | ^^^^^^^^^ + | | + | function or associated item not found in `๐Ÿ‘€` + | help: there is an associated function with a similar name: `full_of_โœจ` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. From f61ae0109dd892617a3959528b47aaddab214a0c Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 9 Sep 2021 15:01:43 +0000 Subject: [PATCH 22/31] Replace ZWJ with nothing in terminal output --- compiler/rustc_errors/src/emitter.rs | 11 ++++++++++- src/test/ui/parser/emoji-identifiers.stderr | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 29f352ae58559..0dc3f184dc601 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2054,8 +2054,17 @@ fn num_decimal_digits(num: usize) -> usize { MAX_DIGITS } +const REPLACEMENTS: &[(char, &str)] = &[ + ('\t', " "), + ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters. +]; + fn replace_tabs(str: &str) -> String { - str.replace('\t', " ") + let mut output = str.to_string(); + for (c, replacement) in REPLACEMENTS { + output = output.replace(*c, replacement); + } + output } fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index 3b17bb01de953..84c3e3962ffec 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -48,10 +48,10 @@ error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜…_a_lot` LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { | ^^^^^^^^^^^^^^^^^^ -error: identifiers cannot contain emojis: `ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily` +error: identifiers cannot contain emojis: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` --> $DIR/emoji-identifiers.rs:1:8 | -LL | struct ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily; +LL | struct ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily; | ^^^^^^^^^^^^^^^^^^ error[E0599]: no function or associated item named `full_ofโœจ` found for struct `๐Ÿ‘€` in the current scope From 8b65c79649be07e1bd3401c98ccf9c260dcdd9e3 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 9 Sep 2021 15:22:29 +0000 Subject: [PATCH 23/31] Fix RustDoc --- src/librustdoc/html/highlight.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index f8fc9243e14b9..22cea66652ba5 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -488,7 +488,7 @@ impl<'a> Classifier<'a> { }, Some(c) => c, }, - TokenKind::RawIdent | TokenKind::UnknownPrefix => { + TokenKind::RawIdent | TokenKind::UnknownPrefix | TokenKind::InvalidIdent => { Class::Ident(self.new_span(before, text)) } TokenKind::Lifetime { .. } => Class::Lifetime, From b43ac6ed5e22fd83d45597a70d90b33647d28489 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 9 Sep 2021 15:41:15 +0000 Subject: [PATCH 24/31] Add `unic-emoji-char` and its dependencies to the allow list --- src/tools/tidy/src/deps.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 5f1267fc3d250..30438ccc9385e 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -82,8 +82,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "bitflags", "block-buffer", "block-padding", - "byteorder", "byte-tools", + "byteorder", "cc", "cfg-if", "chalk-derive", @@ -140,9 +140,9 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "memmap2", "memoffset", "miniz_oxide", - "num_cpus", "num-integer", "num-traits", + "num_cpus", "object", "once_cell", "opaque-debug", @@ -188,8 +188,8 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "serde_json", "sha-1", "sha2", - "smallvec", "sharded-slab", + "smallvec", "snap", "stable_deref_trait", "stacker", @@ -209,6 +209,11 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "tracing-subscriber", "tracing-tree", "typenum", + "unic-char-property", + "unic-char-range", + "unic-common", + "unic-emoji-char", + "unic-ucd-version", "unicode-normalization", "unicode-script", "unicode-security", From 411d64325a467f44fcb570eb423f1a9b204b8746 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 9 Sep 2021 15:55:21 +0000 Subject: [PATCH 25/31] fix fmt --- src/test/ui/parser/emoji-identifiers.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs index 2f4df4cf21619..485fb29af9cdf 100644 --- a/src/test/ui/parser/emoji-identifiers.rs +++ b/src/test/ui/parser/emoji-identifiers.rs @@ -13,4 +13,3 @@ fn main() { let _ = i_like_to_๐Ÿ˜„_a_lot(); //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope //~^ ERROR identifiers cannot contain emojis } - From 4c71eecbf456aafc8c986892cdf01cb1c53c2d22 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Thu, 9 Sep 2021 17:05:03 +0000 Subject: [PATCH 26/31] Account for confusable codepoints when recovering emoji identifiers --- compiler/rustc_parse/src/lexer/mod.rs | 15 +++++++++++++-- compiler/rustc_parse/src/lexer/unicode_chars.rs | 2 +- src/test/ui/parser/emoji-identifiers.rs | 3 ++- src/test/ui/parser/emoji-identifiers.stderr | 17 ++++++++++++++--- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 46501fc2e5956..4ee1b839d839a 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,3 +1,4 @@ +use crate::lexer::unicode_chars::UNICODE_ARRAY; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream}; @@ -191,7 +192,17 @@ impl<'a> StringReader<'a> { } token::Ident(sym, is_raw_ident) } - rustc_lexer::TokenKind::InvalidIdent => { + rustc_lexer::TokenKind::InvalidIdent + // Do not recover an identifier with emojis if the codepoint is a confusable + // with a recoverable substitution token, like `โž–`. + if UNICODE_ARRAY + .iter() + .find(|&&(c, _, _)| { + let sym = self.str_from(start); + sym.chars().count() == 1 && c == sym.chars().next().unwrap() + }) + .is_none() => + { let sym = nfc_normalize(self.str_from(start)); let span = self.mk_sp(start, self.pos); self.sess.bad_unicode_identifiers.borrow_mut().entry(sym).or_default().push(span); @@ -268,7 +279,7 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret), rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), - rustc_lexer::TokenKind::Unknown => { + rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => { let c = self.str_from(start).chars().next().unwrap(); let mut err = self.struct_fatal_span_char(start, self.pos, "unknown start of token", c); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 3eebc088f3fb7..ccd11f06bc582 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -7,7 +7,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks -const UNICODE_ARRAY: &[(char, &str, char)] = &[ +pub(crate) const UNICODE_ARRAY: &[(char, &str, char)] = &[ ('โ€จ', "Line Separator", ' '), ('โ€ฉ', "Paragraph Separator", ' '), ('แš€', "Ogham Space mark", ' '), diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs index 485fb29af9cdf..e07e0573e7594 100644 --- a/src/test/ui/parser/emoji-identifiers.rs +++ b/src/test/ui/parser/emoji-identifiers.rs @@ -10,6 +10,7 @@ fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emojis //~^ ERROR identifiers cannot contain emojis } fn main() { - let _ = i_like_to_๐Ÿ˜„_a_lot(); //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope + let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope //~^ ERROR identifiers cannot contain emojis + //~| ERROR unknown start of token: \u{2796} } diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index 84c3e3962ffec..a73681d91966b 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -1,16 +1,27 @@ +error: unknown start of token: \u{2796} + --> $DIR/emoji-identifiers.rs:13:33 + | +LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; + | ^^ + | +help: Unicode character 'โž–' (Heavy Minus Sign) looks like '-' (Minus/Hyphen), but it is not + | +LL | let _ = i_like_to_๐Ÿ˜„_a_lot() - 4; + | ~ + error[E0425]: cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope --> $DIR/emoji-identifiers.rs:13:13 | LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { | ----------------------------- similarly named function `i_like_to_๐Ÿ˜…_a_lot` defined here ... -LL | let _ = i_like_to_๐Ÿ˜„_a_lot(); +LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_๐Ÿ˜…_a_lot` error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜„_a_lot` --> $DIR/emoji-identifiers.rs:13:13 | -LL | let _ = i_like_to_๐Ÿ˜„_a_lot(); +LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ error: identifiers cannot contain emojis: `full_of_โœจ` @@ -66,7 +77,7 @@ LL | ๐Ÿ‘€::full_ofโœจ() | function or associated item not found in `๐Ÿ‘€` | help: there is an associated function with a similar name: `full_of_โœจ` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0425, E0599. For more information about an error, try `rustc --explain E0425`. From 3750cc6627b70480a6d80e99b7d93a8a8f9001a6 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Sep 2021 07:30:58 +0000 Subject: [PATCH 27/31] review comment: plural of emoji is emoji --- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 2 +- compiler/rustc_session/src/parse.rs | 2 +- src/test/ui/parser/emoji-identifiers.rs | 12 ++++++------ src/test/ui/parser/emoji-identifiers.stderr | 12 ++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f631b46e565d2..aa87a4f53a41c 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -450,7 +450,7 @@ pub fn configure_and_expand( for (ident, spans) in identifiers.drain() { sess.diagnostic().span_err( MultiSpan::from(spans), - &format!("identifiers cannot contain emojis: `{}`", ident), + &format!("identifiers cannot contain emoji: `{}`", ident), ); } }); diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 4ee1b839d839a..b0552dda1177d 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -193,7 +193,7 @@ impl<'a> StringReader<'a> { token::Ident(sym, is_raw_ident) } rustc_lexer::TokenKind::InvalidIdent - // Do not recover an identifier with emojis if the codepoint is a confusable + // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `โž–`. if UNICODE_ARRAY .iter() diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 69d02e6c1ae93..24e0cd1862ff3 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -123,7 +123,7 @@ pub struct ParseSess { /// clashing with keywords in new editions. pub raw_identifier_spans: Lock>, /// Places where identifiers that contain invalid Unicode codepoints but that look like they - /// should be. Useful to avoid bad tokenization when encountering emojis. We group them to + /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to /// provide a single error per unique incorrect identifier. pub bad_unicode_identifiers: Lock>>, source_map: Lrc, diff --git a/src/test/ui/parser/emoji-identifiers.rs b/src/test/ui/parser/emoji-identifiers.rs index e07e0573e7594..ef18939bbb80c 100644 --- a/src/test/ui/parser/emoji-identifiers.rs +++ b/src/test/ui/parser/emoji-identifiers.rs @@ -1,16 +1,16 @@ -struct ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily; //~ ERROR identifiers cannot contain emojis -struct ๐Ÿ‘€; //~ ERROR identifiers cannot contain emojis +struct ABig๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘งFamily; //~ ERROR identifiers cannot contain emoji +struct ๐Ÿ‘€; //~ ERROR identifiers cannot contain emoji impl ๐Ÿ‘€ { - fn full_of_โœจ() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emojis + fn full_of_โœจ() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emoji ๐Ÿ‘€ } } -fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emojis +fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { //~ ERROR identifiers cannot contain emoji ๐Ÿ‘€::full_ofโœจ() //~ ERROR no function or associated item named `full_ofโœจ` found for struct `๐Ÿ‘€` - //~^ ERROR identifiers cannot contain emojis + //~^ ERROR identifiers cannot contain emoji } fn main() { let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; //~ ERROR cannot find function `i_like_to_๐Ÿ˜„_a_lot` in this scope - //~^ ERROR identifiers cannot contain emojis + //~^ ERROR identifiers cannot contain emoji //~| ERROR unknown start of token: \u{2796} } diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index a73681d91966b..a69a9c542d6e9 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -18,25 +18,25 @@ LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_๐Ÿ˜…_a_lot` -error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜„_a_lot` +error: identifiers cannot contain emoji: `i_like_to_๐Ÿ˜„_a_lot` --> $DIR/emoji-identifiers.rs:13:13 | LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ -error: identifiers cannot contain emojis: `full_of_โœจ` +error: identifiers cannot contain emoji: `full_of_โœจ` --> $DIR/emoji-identifiers.rs:4:8 | LL | fn full_of_โœจ() -> ๐Ÿ‘€ { | ^^^^^^^^^^ -error: identifiers cannot contain emojis: `full_ofโœจ` +error: identifiers cannot contain emoji: `full_ofโœจ` --> $DIR/emoji-identifiers.rs:9:8 | LL | ๐Ÿ‘€::full_ofโœจ() | ^^^^^^^^^ -error: identifiers cannot contain emojis: `๐Ÿ‘€` +error: identifiers cannot contain emoji: `๐Ÿ‘€` --> $DIR/emoji-identifiers.rs:2:8 | LL | struct ๐Ÿ‘€; @@ -53,13 +53,13 @@ LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { LL | ๐Ÿ‘€::full_ofโœจ() | ^^ -error: identifiers cannot contain emojis: `i_like_to_๐Ÿ˜…_a_lot` +error: identifiers cannot contain emoji: `i_like_to_๐Ÿ˜…_a_lot` --> $DIR/emoji-identifiers.rs:8:4 | LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { | ^^^^^^^^^^^^^^^^^^ -error: identifiers cannot contain emojis: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` +error: identifiers cannot contain emoji: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` --> $DIR/emoji-identifiers.rs:1:8 | LL | struct ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily; From 109ebdfdf3ef06b7c506123f16f43c1c59da5293 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Sep 2021 07:32:07 +0000 Subject: [PATCH 28/31] `replace_tabs` -> `normalize_whitespace` --- compiler/rustc_errors/src/emitter.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 0dc3f184dc601..47d240b389d64 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -721,7 +721,7 @@ impl EmitterWriter { } let source_string = match file.get_line(line.line_index - 1) { - Some(s) => replace_tabs(&*s), + Some(s) => normalize_whitespace(&*s), None => return Vec::new(), }; @@ -1272,7 +1272,7 @@ impl EmitterWriter { buffer.append(0, ": ", header_style); } for &(ref text, _) in msg.iter() { - buffer.append(0, &replace_tabs(text), header_style); + buffer.append(0, &normalize_whitespace(text), header_style); } } @@ -1526,7 +1526,7 @@ impl EmitterWriter { self.draw_line( &mut buffer, - &replace_tabs(&unannotated_line), + &normalize_whitespace(&unannotated_line), annotated_file.lines[line_idx + 1].line_index - 1, last_buffer_line_num, width_offset, @@ -1648,7 +1648,7 @@ impl EmitterWriter { buffer.puts( row_num - 1, max_line_num_len + 3, - &replace_tabs( + &normalize_whitespace( &*file_lines .file .get_line(file_lines.lines[line_pos].line_index) @@ -1674,7 +1674,7 @@ impl EmitterWriter { } // print the suggestion - buffer.append(row_num, &replace_tabs(line), Style::NoStyle); + buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle); // Colorize addition/replacements with green. for &SubstitutionHighlight { start, end } in highlight_parts { @@ -2059,7 +2059,7 @@ const REPLACEMENTS: &[(char, &str)] = &[ ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters. ]; -fn replace_tabs(str: &str) -> String { +fn normalize_whitespace(str: &str) -> String { let mut output = str.to_string(); for (c, replacement) in REPLACEMENTS { output = output.replace(*c, replacement); From 76713c9a500da133cc9c6a5c524b11852cdec667 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Fri, 10 Sep 2021 07:36:01 +0000 Subject: [PATCH 29/31] udpate comment to be more accurate --- compiler/rustc_lexer/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index a729c0c0bbea3..44b002fa93f42 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -413,8 +413,7 @@ impl Cursor<'_> { let kind = Str { terminated }; Literal { kind, suffix_start } } - // Identifier (this should be checked after other variant that can - // start as identifier). + // Identifier starting with an emoji. Only lexed for graceful error recovery. c if !c.is_ascii() && unic_emoji_char::is_emoji(c) => { self.fake_ident_or_unknown_prefix() } From 30f98073d522ab782b531bd3426c92d6f5dcf881 Mon Sep 17 00:00:00 2001 From: Esteban Kuber Date: Tue, 14 Sep 2021 11:39:49 +0000 Subject: [PATCH 30/31] Sort `FxHashSet`'s contents before emitting errors for consistent output --- compiler/rustc_interface/src/passes.rs | 5 ++- src/test/ui/parser/emoji-identifiers.stderr | 40 ++++++++++----------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aa87a4f53a41c..7071a98b77d15 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -447,7 +447,10 @@ pub fn configure_and_expand( // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| { - for (ident, spans) in identifiers.drain() { + let mut identifiers: Vec<_> = identifiers.drain().collect(); + identifiers.sort_by_key(|&(key, _)| key); + for (ident, mut spans) in identifiers.into_iter() { + spans.sort(); sess.diagnostic().span_err( MultiSpan::from(spans), &format!("identifiers cannot contain emoji: `{}`", ident), diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr index a69a9c542d6e9..5f9263c4c13e7 100644 --- a/src/test/ui/parser/emoji-identifiers.stderr +++ b/src/test/ui/parser/emoji-identifiers.stderr @@ -18,23 +18,11 @@ LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; | ^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `i_like_to_๐Ÿ˜…_a_lot` -error: identifiers cannot contain emoji: `i_like_to_๐Ÿ˜„_a_lot` - --> $DIR/emoji-identifiers.rs:13:13 - | -LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; - | ^^^^^^^^^^^^^^^^^^ - -error: identifiers cannot contain emoji: `full_of_โœจ` - --> $DIR/emoji-identifiers.rs:4:8 - | -LL | fn full_of_โœจ() -> ๐Ÿ‘€ { - | ^^^^^^^^^^ - -error: identifiers cannot contain emoji: `full_ofโœจ` - --> $DIR/emoji-identifiers.rs:9:8 +error: identifiers cannot contain emoji: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` + --> $DIR/emoji-identifiers.rs:1:8 | -LL | ๐Ÿ‘€::full_ofโœจ() - | ^^^^^^^^^ +LL | struct ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily; + | ^^^^^^^^^^^^^^^^^^ error: identifiers cannot contain emoji: `๐Ÿ‘€` --> $DIR/emoji-identifiers.rs:2:8 @@ -53,17 +41,29 @@ LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { LL | ๐Ÿ‘€::full_ofโœจ() | ^^ +error: identifiers cannot contain emoji: `full_of_โœจ` + --> $DIR/emoji-identifiers.rs:4:8 + | +LL | fn full_of_โœจ() -> ๐Ÿ‘€ { + | ^^^^^^^^^^ + error: identifiers cannot contain emoji: `i_like_to_๐Ÿ˜…_a_lot` --> $DIR/emoji-identifiers.rs:8:4 | LL | fn i_like_to_๐Ÿ˜…_a_lot() -> ๐Ÿ‘€ { | ^^^^^^^^^^^^^^^^^^ -error: identifiers cannot contain emoji: `ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily` - --> $DIR/emoji-identifiers.rs:1:8 +error: identifiers cannot contain emoji: `full_ofโœจ` + --> $DIR/emoji-identifiers.rs:9:8 | -LL | struct ABig๐Ÿ‘ฉ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘งFamily; - | ^^^^^^^^^^^^^^^^^^ +LL | ๐Ÿ‘€::full_ofโœจ() + | ^^^^^^^^^ + +error: identifiers cannot contain emoji: `i_like_to_๐Ÿ˜„_a_lot` + --> $DIR/emoji-identifiers.rs:13:13 + | +LL | let _ = i_like_to_๐Ÿ˜„_a_lot() โž– 4; + | ^^^^^^^^^^^^^^^^^^ error[E0599]: no function or associated item named `full_ofโœจ` found for struct `๐Ÿ‘€` in the current scope --> $DIR/emoji-identifiers.rs:9:8 From f9b8191282da80fff41f496d4b2e8e4dcd3502ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Tue, 14 Sep 2021 00:00:00 +0000 Subject: [PATCH 31/31] Remove implementation of `min_align_of` intrinsic Since 88839 `min_align_of` is lowered to AlignOf operator. --- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index b032ee96ce7b0..698742fe98ceb 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -62,15 +62,10 @@ crate fn eval_nullary_intrinsic<'tcx>( ensure_monomorphic_enough(tcx, tp_ty)?; ConstValue::from_bool(tp_ty.needs_drop(tcx, param_env)) } - sym::min_align_of | sym::pref_align_of => { + sym::pref_align_of => { // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough. let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?; - let n = match name { - sym::pref_align_of => layout.align.pref.bytes(), - sym::min_align_of => layout.align.abi.bytes(), - _ => bug!(), - }; - ConstValue::from_machine_usize(n, &tcx) + ConstValue::from_machine_usize(layout.align.pref.bytes(), &tcx) } sym::type_id => { ensure_monomorphic_enough(tcx, tp_ty)?;