Merge from rustc

This commit is contained in:
Ben Kimock 2023-03-14 20:58:48 -04:00
commit f18c39e98c
903 changed files with 23157 additions and 9653 deletions

1
.gitattributes vendored
View File

@ -9,7 +9,6 @@
src/etc/installer/gfx/* binary src/etc/installer/gfx/* binary
src/vendor/** -text src/vendor/** -text
Cargo.lock linguist-generated=false Cargo.lock linguist-generated=false
config.toml.example linguist-language=TOML
# Older git versions try to fix line endings on images and fonts, this prevents it. # Older git versions try to fix line endings on images and fonts, this prevents it.
*.png binary *.png binary

View File

@ -443,7 +443,7 @@ jobs:
os: windows-latest-xl os: windows-latest-xl
- name: dist-x86_64-msvc - name: dist-x86_64-msvc
env: env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler --set rust.lto=thin" RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
DIST_REQUIRE_ALL_TOOLS: 1 DIST_REQUIRE_ALL_TOOLS: 1
os: windows-latest-xl os: windows-latest-xl

View File

@ -1,13 +1,79 @@
# WARNING: this metadata is currently incomplete, do not rely on it yet.
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files-Excluded: Files-Excluded:
src/llvm-project src/llvm-project
Files: * # Note that we're explicitly listing the individual files at the root of the
# repository rather than just having `Files: *`. This is explicitly done to
# help downstream forks of the Rust compiler: this way, the files they add
# won't be automatically marked as authored by the Rust project.
Files: compiler/*
library/*
tests/*
src/*
.github/*
Cargo.lock
Cargo.toml
CODE_OF_CONDUCT.md
config.example.toml
configure
CONTRIBUTING.md
COPYRIGHT
LICENSE-APACHE
LICENSE-MIT
README.md
RELEASES.md
rustfmt.toml
triagebot.toml
x
x.ps1
x.py
.editorconfig
.git-blame-ignore-revs
.gitattributes
.gitignore
.gitmodules
.mailmap
Copyright: The Rust Project Developers (see https://thanks.rust-lang.org) Copyright: The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT or Apache-2.0 License: MIT or Apache-2.0
Files: compiler/rustc_apfloat/*
Copyright: LLVM APFloat authors
The Rust Project Developers (see https://thanks.rust-lang.org)
License: NCSA AND (MIT OR Apache-2.0)
Files: compiler/rustc_codegen_cranelift/src/cranelift_native.rs
Copyright: The Cranelift Project Developers
The Rust Project Developers (see https://thanks.rust-lang.org)
License: Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT)
Files: compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
Copyright: LLVM authors
The Rust Project Developers (see https://thanks.rust-lang.org)
License: Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT)
Files: library/core/src/unicode/unicode_data.rs
Copyright: 1991-2022 Unicode, Inc. All rights reserved.
License: Unicode-DFS-2016
Files: library/std/src/sync/mpmc/*
Copyright: 2019 The Crossbeam Project Developers
The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT OR Apache-2.0
Files: library/std/src/sys/unix/locks/fuchsia_mutex.rs
Copyright: 2016 The Fuchsia Authors
The Rust Project Developers (see https://thanks.rust-lang.org)
License: BSD-2-Clause AND (MIT OR Apache-2.0)
Files: src/test/rustdoc/auxiliary/enum-primitive.rs
Copyright: 2015 Anders Kaseorg <andersk@mit.edu>
License: MIT
Files: src/librustdoc/html/static/fonts/FiraSans* Files: src/librustdoc/html/static/fonts/FiraSans*
Copyright: 2014, Mozilla Foundation, 2014, Telefonica S.A. Copyright: 2014, Mozilla Foundation
2014, Telefonica S.A.
License: OFL-1.1 License: OFL-1.1
Files: src/librustdoc/html/static/fonts/NanumBarun* Files: src/librustdoc/html/static/fonts/NanumBarun*
@ -15,9 +81,19 @@ Copyright: 2010 NAVER Corporation
License: OFL-1.1 License: OFL-1.1
Files: src/librustdoc/html/static/fonts/SourceCodePro* Files: src/librustdoc/html/static/fonts/SourceCodePro*
Copyright: 2010, 2012 Adobe Systems Incorporated src/librustdoc/html/static/fonts/SourceSerif4*
Copyright: 2010, 2012, 2014-2023, Adobe Systems Incorporated
License: OFL-1.1 License: OFL-1.1
Files: src/librustdoc/html/static/fonts/SourceSerif4* Files: src/librustdoc/html/static/css/normalize.css
Copyright: 2014-2021 Adobe Systems Incorporated Copyright: Nicolas Gallagher and Jonathan Neal
License: OFL-1.1 License: MIT
Files: src/librustdoc/html/static/css/themes/ayu.css
Copyright: Ike Ku, Jessica Stokes, Leon Guan
The Rust Project Developers (see https://thanks.rust-lang.org)
License: MIT OR Apache-2.0
Files: src/doc/rustc-dev-guide/mermaid.min.js
Copyright: Knut Sveidqvist
License: MIT

View File

@ -738,7 +738,7 @@ dependencies = [
[[package]] [[package]]
name = "clippy" name = "clippy"
version = "0.1.69" version = "0.1.70"
dependencies = [ dependencies = [
"clap 4.1.4", "clap 4.1.4",
"clippy_lints", "clippy_lints",
@ -781,7 +781,7 @@ dependencies = [
[[package]] [[package]]
name = "clippy_lints" name = "clippy_lints"
version = "0.1.69" version = "0.1.70"
dependencies = [ dependencies = [
"cargo_metadata 0.15.3", "cargo_metadata 0.15.3",
"clippy_utils", "clippy_utils",
@ -804,7 +804,7 @@ dependencies = [
[[package]] [[package]]
name = "clippy_utils" name = "clippy_utils"
version = "0.1.69" version = "0.1.70"
dependencies = [ dependencies = [
"arrayvec 0.7.0", "arrayvec 0.7.0",
"if_chain", "if_chain",
@ -1150,7 +1150,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
[[package]] [[package]]
name = "declare_clippy_lint" name = "declare_clippy_lint"
version = "0.1.69" version = "0.1.70"
dependencies = [ dependencies = [
"itertools", "itertools",
"quote", "quote",

View File

@ -0,0 +1,9 @@
Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

15
LICENSES/NCSA.txt Normal file
View File

@ -0,0 +1,15 @@
University of Illinois/NCSA Open Source License
Copyright (c) <Year> <Owner Organization Name>. All rights reserved.
Developed by: <Name of Development Group> <Name of Institution> <URL for Development Group/Institution>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution.
* Neither the names of <Name of Development Group, Name of Institution>, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.

View File

@ -0,0 +1,22 @@
UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
Unicode Data Files include all data files under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
Unicode Data Files do not include PDF online code charts under the directory http://www.unicode.org/Public/.
Software includes any source code published in the Unicode Standard or under the directories http://www.unicode.org/Public/, http://www.unicode.org/reports/, http://www.unicode.org/cldr/data/, http://source.icu-project.org/repos/icu/, and http://www.unicode.org/utility/trac/browser/.
NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"), YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE.
COPYRIGHT AND PERMISSION NOTICE
Copyright © 1991-2016 Unicode, Inc. All rights reserved. Distributed under the Terms of Use in http://www.unicode.org/copyright.html.
Permission is hereby granted, free of charge, to any person obtaining a copy of the Unicode data files and any associated documentation (the "Data Files") or Unicode software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either
(a) this copyright and permission notice appear with all copies of the Data Files or Software, or
(b) this copyright and permission notice appear in associated Documentation.
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.

View File

@ -99,7 +99,7 @@ See [the rustc-dev-guide for more info][sysllvm].
The Rust build system uses a file named `config.toml` in the root of the The Rust build system uses a file named `config.toml` in the root of the
source tree to determine various configuration settings for the build. source tree to determine various configuration settings for the build.
Set up the defaults intended for distros to get started. You can see a full Set up the defaults intended for distros to get started. You can see a full
list of options in `config.toml.example`. list of options in `config.example.toml`.
```sh ```sh
printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml printf 'profile = "user" \nchangelog-seen = 2 \n' > config.toml

View File

@ -24,6 +24,15 @@
// The two crates we link to here, `std` and `rustc_driver`, are both dynamic // The two crates we link to here, `std` and `rustc_driver`, are both dynamic
// libraries. So we must reference jemalloc symbols one way or another, because // libraries. So we must reference jemalloc symbols one way or another, because
// this file is the only object code in the rustc executable. // this file is the only object code in the rustc executable.
//
// NOTE: if you are reading this comment because you want to set a custom `global_allocator` for
// benchmarking, consider using the benchmarks in the `rustc-perf` collector suite instead:
// https://github.com/rust-lang/rustc-perf/blob/master/collector/README.md#profiling
//
// NOTE: if you are reading this comment because you want to replace jemalloc with another allocator
// to compare their performance, see
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
// for an example of how to do so.
#[unix_sigpipe = "sig_dfl"] #[unix_sigpipe = "sig_dfl"]
fn main() { fn main() {

View File

@ -1230,7 +1230,6 @@ impl Expr {
pub fn precedence(&self) -> ExprPrecedence { pub fn precedence(&self) -> ExprPrecedence {
match self.kind { match self.kind {
ExprKind::Box(_) => ExprPrecedence::Box,
ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::Call(..) => ExprPrecedence::Call,
@ -1291,8 +1290,7 @@ impl Expr {
/// To a first-order approximation, is this a pattern? /// To a first-order approximation, is this a pattern?
pub fn is_approximately_pattern(&self) -> bool { pub fn is_approximately_pattern(&self) -> bool {
match &self.peel_parens().kind { match &self.peel_parens().kind {
ExprKind::Box(_) ExprKind::Array(_)
| ExprKind::Array(_)
| ExprKind::Call(_, _) | ExprKind::Call(_, _)
| ExprKind::Tup(_) | ExprKind::Tup(_)
| ExprKind::Lit(_) | ExprKind::Lit(_)
@ -1363,8 +1361,6 @@ pub struct StructExpr {
#[derive(Clone, Encodable, Decodable, Debug)] #[derive(Clone, Encodable, Decodable, Debug)]
pub enum ExprKind { pub enum ExprKind {
/// A `box x` expression.
Box(P<Expr>),
/// An array (`[a, b, c, d]`) /// An array (`[a, b, c, d]`)
Array(ThinVec<P<Expr>>), Array(ThinVec<P<Expr>>),
/// Allow anonymous constants from an inline `const` block /// Allow anonymous constants from an inline `const` block

View File

@ -1316,7 +1316,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
vis: &mut T, vis: &mut T,
) { ) {
match kind { match kind {
ExprKind::Box(expr) => vis.visit_expr(expr),
ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis),
ExprKind::ConstBlock(anon_const) => { ExprKind::ConstBlock(anon_const) => {
vis.visit_anon_const(anon_const); vis.visit_anon_const(anon_const);

View File

@ -35,7 +35,6 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
| Assign(_, e, _) | Assign(_, e, _)
| AssignOp(_, _, e) | AssignOp(_, _, e)
| Binary(_, _, e) | Binary(_, _, e)
| Box(e)
| Break(_, Some(e)) | Break(_, Some(e))
| Let(_, e, _) | Let(_, e, _)
| Range(_, Some(e), _) | Range(_, Some(e), _)

View File

@ -772,7 +772,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
walk_list!(visitor, visit_attribute, expression.attrs.iter()); walk_list!(visitor, visit_attribute, expression.attrs.iter());
match &expression.kind { match &expression.kind {
ExprKind::Box(subexpression) => visitor.visit_expr(subexpression),
ExprKind::Array(subexpressions) => { ExprKind::Array(subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions); walk_list!(visitor, visit_expr, subexpressions);
} }

View File

@ -32,7 +32,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ensure_sufficient_stack(|| { ensure_sufficient_stack(|| {
match &e.kind { match &e.kind {
// Paranthesis expression does not have a HirId and is handled specially. // Parenthesis expression does not have a HirId and is handled specially.
ExprKind::Paren(ex) => { ExprKind::Paren(ex) => {
let mut ex = self.lower_expr_mut(ex); let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span. // Include parens in span, but only if it is a super-span.
@ -63,6 +63,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::ForLoop(pat, head, body, opt_label) => { ExprKind::ForLoop(pat, head, body, opt_label) => {
return self.lower_expr_for(e, pat, head, body, *opt_label); return self.lower_expr_for(e, pat, head, body, *opt_label);
} }
// Similarly, async blocks do not use `e.id` but rather `closure_node_id`.
ExprKind::Async(capture_clause, closure_node_id, block) => {
let hir_id = self.lower_node_id(*closure_node_id);
self.lower_attrs(hir_id, &e.attrs);
return self.make_async_expr(
*capture_clause,
hir_id,
*closure_node_id,
None,
e.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
);
}
_ => (), _ => (),
} }
@ -70,7 +84,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_attrs(hir_id, &e.attrs); self.lower_attrs(hir_id, &e.attrs);
let kind = match &e.kind { let kind = match &e.kind {
ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(anon_const) => { ExprKind::ConstBlock(anon_const) => {
let anon_const = self.lower_anon_const(anon_const); let anon_const = self.lower_anon_const(anon_const);
@ -174,15 +187,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))),
hir::MatchSource::Normal, hir::MatchSource::Normal,
), ),
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
*capture_clause,
hir_id,
*closure_node_id,
None,
e.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
ExprKind::Await(expr) => { ExprKind::Await(expr) => {
let dot_await_span = if expr.span.hi() < e.span.hi() { let dot_await_span = if expr.span.hi() < e.span.hi() {
let span_with_whitespace = self let span_with_whitespace = self
@ -316,7 +320,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
), ),
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"), ExprKind::Paren(_) | ExprKind::ForLoop(..) | ExprKind::Async(..) => {
unreachable!("already handled")
}
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
}; };
@ -578,9 +584,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// This results in: /// This results in:
/// ///
/// ```text /// ```text
/// std::future::identity_future(static move? |_task_context| -> <ret_ty> { /// static move? |_task_context| -> <ret_ty> {
/// <body> /// <body>
/// }) /// }
/// ``` /// ```
pub(super) fn make_async_expr( pub(super) fn make_async_expr(
&mut self, &mut self,
@ -591,7 +597,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
span: Span, span: Span,
async_gen_kind: hir::AsyncGeneratorKind, async_gen_kind: hir::AsyncGeneratorKind,
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
) -> hir::ExprKind<'hir> { ) -> hir::Expr<'hir> {
let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span)));
// Resume argument type: `ResumeTy` // Resume argument type: `ResumeTy`
@ -656,13 +662,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
}; };
let hir_id = self.lower_node_id(closure_node_id); let hir_id = self.lower_node_id(closure_node_id);
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
if self.tcx.features().closure_track_caller if self.tcx.features().closure_track_caller
&& let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id)
&& attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller))
{ {
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
self.lower_attrs( self.lower_attrs(
hir_id, hir_id,
&[Attribute { &[Attribute {
@ -681,22 +686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
); );
} }
let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }
// FIXME(swatinem):
// For some reason, the async block needs to flow through *any*
// call (like the identity function), as otherwise type and lifetime
// inference have a hard time figuring things out.
// Without this, we would get:
// E0720 in tests/ui/impl-trait/in-trait/default-body-with-rpit.rs
// E0700 in tests/ui/self/self_lifetime-async.rs
// `future::identity_future`:
let identity_future =
self.expr_lang_item_path(unstable_span, hir::LangItem::IdentityFuture, None);
// `future::identity_future(generator)`:
hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator])
} }
/// Desugar `<expr>.await` into: /// Desugar `<expr>.await` into:
@ -1002,7 +992,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} }
// Transform `async |x: u8| -> X { ... }` into // Transform `async |x: u8| -> X { ... }` into
// `|x: u8| identity_future(|| -> X { ... })`. // `|x: u8| || -> X { ... }`.
let body_id = this.lower_fn_body(&outer_decl, |this| { let body_id = this.lower_fn_body(&outer_decl, |this| {
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
@ -1011,7 +1001,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None None
}; };
let async_body = this.make_async_expr( this.make_async_expr(
capture_clause, capture_clause,
closure_hir_id, closure_hir_id,
inner_closure_id, inner_closure_id,
@ -1019,8 +1009,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
body.span, body.span,
hir::AsyncGeneratorKind::Closure, hir::AsyncGeneratorKind::Closure,
|this| this.with_new_scopes(|this| this.lower_expr_mut(body)), |this| this.with_new_scopes(|this| this.lower_expr_mut(body)),
); )
this.expr(fn_decl_span, async_body)
}); });
body_id body_id
}); });

View File

@ -1180,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}, },
); );
(this.arena.alloc_from_iter(parameters), this.expr(body.span, async_expr)) (this.arena.alloc_from_iter(parameters), async_expr)
}) })
} }

View File

@ -92,7 +92,7 @@ mod lifetime_collector;
mod pat; mod pat;
mod path; mod path;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
struct LoweringContext<'a, 'hir> { struct LoweringContext<'a, 'hir> {
tcx: TyCtxt<'hir>, tcx: TyCtxt<'hir>,
@ -435,7 +435,9 @@ fn compute_hir_hash(
pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
let sess = tcx.sess; let sess = tcx.sess;
tcx.ensure().output_filenames(()); // Queries that borrow `resolver_for_lowering`.
tcx.ensure_with_value().output_filenames(());
tcx.ensure_with_value().early_lint_checks(());
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
@ -463,8 +465,10 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
rustc_span::hygiene::clear_syntax_context_map(); rustc_span::hygiene::clear_syntax_context_map();
} }
let hir_hash = compute_hir_hash(tcx, &owners); // Don't hash unless necessary, because it's expensive.
hir::Crate { owners, hir_hash } let opt_hir_hash =
if tcx.sess.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
hir::Crate { owners, opt_hir_hash }
} }
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
@ -657,42 +661,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
bodies.sort_by_key(|(k, _)| *k); bodies.sort_by_key(|(k, _)| *k);
let bodies = SortedMap::from_presorted_elements(bodies); let bodies = SortedMap::from_presorted_elements(bodies);
let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
let (nodes, parenting) = // Don't hash unless necessary, because it's expensive.
index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies); let (opt_hash_including_bodies, attrs_hash) = if self.tcx.sess.needs_crate_hash() {
let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies }; self.tcx.with_stable_hashing_context(|mut hcx| {
let attrs = { let mut stable_hasher = StableHasher::new();
let hash = self.tcx.with_stable_hashing_context(|mut hcx| { hcx.with_hir_bodies(node.def_id(), &bodies, |hcx| {
node.hash_stable(hcx, &mut stable_hasher)
});
let h1 = stable_hasher.finish();
let mut stable_hasher = StableHasher::new(); let mut stable_hasher = StableHasher::new();
attrs.hash_stable(&mut hcx, &mut stable_hasher); attrs.hash_stable(&mut hcx, &mut stable_hasher);
stable_hasher.finish() let h2 = stable_hasher.finish();
});
hir::AttributeMap { map: attrs, hash } (Some(h1), Some(h2))
})
} else {
(None, None)
}; };
let (nodes, parenting) =
index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash };
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
} }
/// Hash the HIR node twice, one deep and one shallow hash. This allows to differentiate
/// queries which depend on the full HIR tree and those which only depend on the item signature.
fn hash_owner(
&mut self,
node: hir::OwnerNode<'hir>,
bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
) -> (Fingerprint, Fingerprint) {
self.tcx.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
hcx.with_hir_bodies(node.def_id(), bodies, |hcx| {
node.hash_stable(hcx, &mut stable_hasher)
});
let hash_including_bodies = stable_hasher.finish();
let mut stable_hasher = StableHasher::new();
hcx.without_hir_bodies(|hcx| node.hash_stable(hcx, &mut stable_hasher));
let hash_without_bodies = stable_hasher.finish();
(hash_including_bodies, hash_without_bodies)
})
}
/// This method allocates a new `HirId` for the given `NodeId` and stores it in /// This method allocates a new `HirId` for the given `NodeId` and stores it in
/// the `LoweringContext`'s `NodeId => HirId` map. /// the `LoweringContext`'s `NodeId => HirId` map.
/// Take care not to call this method if the resulting `HirId` is then not /// Take care not to call this method if the resulting `HirId` is then not

View File

@ -337,9 +337,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::TyKind::Never => { ast::TyKind::Never => {
gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental");
} }
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => {
gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable");
}
_ => {} _ => {}
} }
visit::walk_ty(self, ty) visit::walk_ty(self, ty)
@ -395,14 +392,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_expr(&mut self, e: &'a ast::Expr) { fn visit_expr(&mut self, e: &'a ast::Expr) {
match e.kind { match e.kind {
ast::ExprKind::Box(_) => {
gate_feature_post!(
&self,
box_syntax,
e.span,
"box expression syntax is experimental; you can call `Box::new` instead"
);
}
ast::ExprKind::Type(..) => { ast::ExprKind::Type(..) => {
if self.sess.parse_sess.span_diagnostic.err_count() == 0 { if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
// To avoid noise about type ascription in common syntax errors, // To avoid noise about type ascription in common syntax errors,
@ -425,14 +414,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ExprKind::TryBlock(_) => { ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental"); gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
} }
ast::ExprKind::Closure(box ast::Closure { constness: ast::Const::Yes(_), .. }) => {
gate_feature_post!(
&self,
const_closures,
e.span,
"const closures are experimental"
);
}
_ => {} _ => {}
} }
visit::walk_expr(self, e) visit::walk_expr(self, e)
@ -594,6 +575,8 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(inline_const_pat, "inline-const in pattern position is experimental"); gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
gate_all!(associated_const_equality, "associated const equality is incomplete"); gate_all!(associated_const_equality, "associated const equality is incomplete");
gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(yeet_expr, "`do yeet` expression is experimental");
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
gate_all!(const_closures, "const closures are experimental");
// All uses of `gate_all!` below this point were added in #65742, // All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded). // and subsequently disabled (with the non-early gating readded).
@ -613,7 +596,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(box_patterns, "box pattern syntax is experimental"); gate_all!(box_patterns, "box pattern syntax is experimental");
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental"); gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
gate_all!(try_blocks, "`try` blocks are unstable"); gate_all!(try_blocks, "`try` blocks are unstable");
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
gate_all!(type_ascription, "type ascription is experimental"); gate_all!(type_ascription, "type ascription is experimental");
visit::walk_crate(&mut visitor, krate); visit::walk_crate(&mut visitor, krate);

View File

@ -21,4 +21,4 @@ pub mod feature_gate;
pub mod node_count; pub mod node_count;
pub mod show_span; pub mod show_span;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }

View File

@ -244,6 +244,10 @@ impl<'a> State<'a> {
(&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
parser::PREC_FORCE_PAREN parser::PREC_FORCE_PAREN
} }
// For a binary expression like `(match () { _ => a }) OP b`, the parens are required
// otherwise the parser would interpret `match () { _ => a }` as a statement,
// with the remaining `OP b` not making sense. So we force parens.
(&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN,
_ => left_prec, _ => left_prec,
}; };
@ -292,10 +296,6 @@ impl<'a> State<'a> {
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
self.ann.pre(self, AnnNode::Expr(expr)); self.ann.pre(self, AnnNode::Expr(expr));
match &expr.kind { match &expr.kind {
ast::ExprKind::Box(expr) => {
self.word_space("box");
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
}
ast::ExprKind::Array(exprs) => { ast::ExprKind::Array(exprs) => {
self.print_expr_vec(exprs); self.print_expr_vec(exprs);
} }

View File

@ -26,4 +26,4 @@ pub use rustc_ast::attr::*;
pub(crate) use rustc_ast::HashStableContext; pub(crate) use rustc_ast::HashStableContext;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }

View File

@ -1985,16 +1985,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (place_desc, note) = if let Some(place_desc) = opt_place_desc { let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
match self.body.local_kind(local) { match self.body.local_kind(local) {
LocalKind::ReturnPointer | LocalKind::Temp => { LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
bug!("temporary or return pointer with a name") "local variable "
} }
LocalKind::Var => "local variable ",
LocalKind::Arg LocalKind::Arg
if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
{ {
"variable captured by `move` " "variable captured by `move` "
} }
LocalKind::Arg => "function parameter ", LocalKind::Arg => "function parameter ",
LocalKind::ReturnPointer | LocalKind::Temp => {
bug!("temporary or return pointer with a name")
}
} }
} else { } else {
"local data " "local data "
@ -2008,16 +2010,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
let local = root_place.local; let local = root_place.local;
match self.body.local_kind(local) { match self.body.local_kind(local) {
LocalKind::ReturnPointer | LocalKind::Temp => {
("temporary value".to_string(), "temporary value created here".to_string())
}
LocalKind::Arg => ( LocalKind::Arg => (
"function parameter".to_string(), "function parameter".to_string(),
"function parameter borrowed here".to_string(), "function parameter borrowed here".to_string(),
), ),
LocalKind::Var => { LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
("local binding".to_string(), "local binding introduced here".to_string()) ("local binding".to_string(), "local binding introduced here".to_string())
} }
LocalKind::ReturnPointer | LocalKind::Temp => {
("temporary value".to_string(), "temporary value created here".to_string())
}
} }
}; };
@ -2482,15 +2484,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let (place_description, assigned_span) = match local_decl { let (place_description, assigned_span) = match local_decl {
Some(LocalDecl { Some(LocalDecl {
local_info: local_info:
Some(box LocalInfo::User( ClearCrossCrate::Set(
ClearCrossCrate::Clear box LocalInfo::User(BindingForm::Var(VarBindingForm {
| ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
opt_match_place: None, opt_match_place: None,
.. ..
})), }))
)) | box LocalInfo::StaticRef { .. }
| Some(box LocalInfo::StaticRef { .. }) | box LocalInfo::Boring,
| None, ),
.. ..
}) })
| None => (self.describe_any_place(place.as_ref()), assigned_span), | None => (self.describe_any_place(place.as_ref()), assigned_span),

View File

@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor;
use rustc_index::vec::IndexVec; use rustc_index::vec::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::{ use rustc_middle::mir::{
Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
Statement, StatementKind, TerminatorKind, Rvalue, Statement, StatementKind, TerminatorKind,
}; };
use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_middle::ty::{self, RegionVid, TyCtxt};
@ -220,7 +220,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
); );
err.span_label(body.source_info(drop_loc).span, message); err.span_label(body.source_info(drop_loc).span, message);
if let Some(info) = &local_decl.is_block_tail { if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
if info.tail_result_is_ignored { if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains // #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful. // the second borrow, this suggestion isn't helpful.

View File

@ -196,10 +196,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if self.body.local_decls[local].is_ref_for_guard() { if self.body.local_decls[local].is_ref_for_guard() {
continue; continue;
} }
if let Some(box LocalInfo::StaticRef { def_id, .. }) = if let LocalInfo::StaticRef { def_id, .. } =
&self.body.local_decls[local].local_info *self.body.local_decls[local].local_info()
{ {
buf.push_str(self.infcx.tcx.item_name(*def_id).as_str()); buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
ok = Ok(()); ok = Ok(());
continue; continue;
} }

View File

@ -102,14 +102,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// //
// opt_match_place is None for let [mut] x = ... statements, // opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression // whether or not the right-hand side is a place expression
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( if let LocalInfo::User(BindingForm::Var(VarBindingForm {
VarBindingForm { opt_match_place: Some((opt_match_place, match_span)),
opt_match_place: Some((opt_match_place, match_span)), binding_mode: _,
binding_mode: _, opt_ty_info: _,
opt_ty_info: _, pat_span: _,
pat_span: _, })) = *local_decl.local_info()
},
)))) = local_decl.local_info
{ {
let stmt_source_info = self.body.source_info(location); let stmt_source_info = self.body.source_info(location);
self.append_binding_error( self.append_binding_error(
@ -478,9 +476,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let mut suggestions: Vec<(Span, String, String)> = Vec::new(); let mut suggestions: Vec<(Span, String, String)> = Vec::new();
for local in binds_to { for local in binds_to {
let bind_to = &self.body.local_decls[*local]; let bind_to = &self.body.local_decls[*local];
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) =
VarBindingForm { pat_span, .. }, *bind_to.local_info()
)))) = bind_to.local_info
{ {
let Ok(pat_snippet) = let Ok(pat_snippet) =
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; }; self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };

View File

@ -7,7 +7,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{ use rustc_middle::{
hir::place::PlaceBase, hir::place::PlaceBase,
mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location}, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
}; };
use rustc_span::source_map::DesugaringKind; use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol}; use rustc_span::symbol::{kw, Symbol};
@ -105,8 +105,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
reason = String::new(); reason = String::new();
} else { } else {
item_msg = access_place_desc; item_msg = access_place_desc;
let local_info = &self.body.local_decls[local].local_info; let local_info = self.body.local_decls[local].local_info();
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { if let LocalInfo::StaticRef { def_id, .. } = *local_info {
let static_name = &self.infcx.tcx.item_name(def_id); let static_name = &self.infcx.tcx.item_name(def_id);
reason = format!(", as `{static_name}` is an immutable static item"); reason = format!(", as `{static_name}` is an immutable static item");
} else { } else {
@ -305,15 +305,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.. ..
}) = &self.body[location.block].statements.get(location.statement_index) }) = &self.body[location.block].statements.get(location.statement_index)
{ {
match decl.local_info { match *decl.local_info() {
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
mir::VarBindingForm { binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
binding_mode: ty::BindingMode::BindByValue(Mutability::Not), opt_ty_info: Some(sp),
opt_ty_info: Some(sp), opt_match_place: _,
opt_match_place: _, pat_span: _,
pat_span: _, })) => {
},
)))) => {
if suggest { if suggest {
err.span_note(sp, "the binding is already a mutable borrow"); err.span_note(sp, "the binding is already a mutable borrow");
} }
@ -346,10 +344,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
} else if decl.mutability.is_not() { } else if decl.mutability.is_not() {
if matches!( if matches!(
decl.local_info, decl.local_info(),
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
hir::ImplicitSelfKind::MutRef
),)))
) { ) {
err.note( err.note(
"as `Self` may be unsized, this call attempts to take `&mut &mut self`", "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
@ -482,22 +478,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match self.local_names[local] { match self.local_names[local] {
Some(name) if !local_decl.from_compiler_desugaring() => { Some(name) if !local_decl.from_compiler_desugaring() => {
let label = match local_decl.local_info.as_deref().unwrap() { let label = match *local_decl.local_info() {
LocalInfo::User(ClearCrossCrate::Set( LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
mir::BindingForm::ImplicitSelf(_),
)) => {
let (span, suggestion) = let (span, suggestion) =
suggest_ampmut_self(self.infcx.tcx, local_decl); suggest_ampmut_self(self.infcx.tcx, local_decl);
Some((true, span, suggestion)) Some((true, span, suggestion))
} }
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
mir::VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_),
binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info,
opt_ty_info, ..
.. })) => {
},
))) => {
// check if the RHS is from desugaring // check if the RHS is from desugaring
let opt_assignment_rhs_span = let opt_assignment_rhs_span =
self.body.find_assignments(local).first().map(|&location| { self.body.find_assignments(local).first().map(|&location| {
@ -534,16 +526,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.infcx.tcx, self.infcx.tcx,
local_decl, local_decl,
opt_assignment_rhs_span, opt_assignment_rhs_span,
*opt_ty_info, opt_ty_info,
) )
} else { } else {
match local_decl.local_info.as_deref() { match local_decl.local_info() {
Some(LocalInfo::User(ClearCrossCrate::Set( LocalInfo::User(mir::BindingForm::Var(
mir::BindingForm::Var(mir::VarBindingForm { mir::VarBindingForm {
opt_ty_info: None, opt_ty_info: None, ..
.. },
}), )) => {
))) => {
let (span, sugg) = suggest_ampmut_self( let (span, sugg) = suggest_ampmut_self(
self.infcx.tcx, self.infcx.tcx,
local_decl, local_decl,
@ -555,7 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
self.infcx.tcx, self.infcx.tcx,
local_decl, local_decl,
opt_assignment_rhs_span, opt_assignment_rhs_span,
*opt_ty_info, opt_ty_info,
), ),
} }
}; };
@ -564,21 +555,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
} }
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
mir::VarBindingForm { binding_mode: ty::BindingMode::BindByReference(_),
binding_mode: ty::BindingMode::BindByReference(_), ..
.. })) => {
},
))) => {
let pattern_span = local_decl.source_info.span; let pattern_span = local_decl.source_info.span;
suggest_ref_mut(self.infcx.tcx, pattern_span) suggest_ref_mut(self.infcx.tcx, pattern_span)
.map(|replacement| (true, pattern_span, replacement)) .map(|replacement| (true, pattern_span, replacement))
} }
LocalInfo::User(ClearCrossCrate::Clear) => {
bug!("saw cleared local state")
}
_ => unreachable!(), _ => unreachable!(),
}; };
@ -1151,20 +1136,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
match local_decl.local_info.as_deref() { match *local_decl.local_info() {
// Check if mutably borrowing a mutable reference. // Check if mutably borrowing a mutable reference.
Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
mir::VarBindingForm { binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
binding_mode: ty::BindingMode::BindByValue(Mutability::Not), .. ..
}, })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
)))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => {
// Check if the user variable is a `&mut self` and we can therefore // Check if the user variable is a `&mut self` and we can therefore
// suggest removing the `&mut`. // suggest removing the `&mut`.
// //
// Deliberately fall into this case for all implicit self types, // Deliberately fall into this case for all implicit self types,
// so that we don't fall in to the next case with them. // so that we don't fall in to the next case with them.
*kind == hir::ImplicitSelfKind::MutRef kind == hir::ImplicitSelfKind::MutRef
} }
_ if Some(kw::SelfLower) == local_name => { _ if Some(kw::SelfLower) == local_name => {
// Otherwise, check if the name is the `self` keyword - in which case // Otherwise, check if the name is the `self` keyword - in which case

View File

@ -100,7 +100,7 @@ use places_conflict::{places_conflict, PlaceConflictBias};
use region_infer::RegionInferenceContext; use region_infer::RegionInferenceContext;
use renumber::RegionCtxt; use renumber::RegionCtxt;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
// FIXME(eddyb) perhaps move this somewhere more centrally. // FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)] #[derive(Debug)]

View File

@ -325,7 +325,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
if errors.is_empty() { if errors.is_empty() {
definition_ty definition_ty
} else { } else {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
self.tcx.ty_error(reported) self.tcx.ty_error(reported)
} }
} }

View File

@ -1180,10 +1180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
} }
} }
Some(l) Some(l)
if matches!( if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) =>
body.local_decls[l].local_info,
Some(box LocalInfo::AggregateTemp)
) =>
{ {
ConstraintCategory::Usage ConstraintCategory::Usage
} }
@ -1684,7 +1681,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// - maybe we should make that a warning. // - maybe we should make that a warning.
return; return;
} }
LocalKind::Var | LocalKind::Temp => {} LocalKind::Temp => {}
} }
// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls

View File

@ -203,17 +203,6 @@ pub fn parse_asm_args<'a>(
// Validate the order of named, positional & explicit register operands and // Validate the order of named, positional & explicit register operands and
// clobber_abi/options. We do this at the end once we have the full span // clobber_abi/options. We do this at the end once we have the full span
// of the argument available. // of the argument available.
if !args.options_spans.is_empty() {
diag.struct_span_err(span, "arguments are not allowed after options")
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
} else if let Some((_, abi_span)) = args.clobber_abis.last() {
diag.struct_span_err(span, "arguments are not allowed after clobber_abi")
.span_label(*abi_span, "clobber_abi")
.span_label(span, "argument")
.emit();
}
if explicit_reg { if explicit_reg {
if name.is_some() { if name.is_some() {
diag.struct_span_err(span, "explicit register arguments cannot have names").emit(); diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
@ -227,17 +216,6 @@ pub fn parse_asm_args<'a>(
.emit(); .emit();
continue; continue;
} }
if !args.reg_args.is_empty() {
let mut err = diag.struct_span_err(
span,
"named arguments cannot follow explicit register arguments",
);
err.span_label(span, "named argument");
for pos in &args.reg_args {
err.span_label(args.operands[*pos].1, "explicit register argument");
}
err.emit();
}
args.named_args.insert(name, slot); args.named_args.insert(name, slot);
} else { } else {
if !args.named_args.is_empty() || !args.reg_args.is_empty() { if !args.named_args.is_empty() || !args.reg_args.is_empty() {
@ -478,15 +456,6 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
let full_span = span_start.to(p.prev_token.span); let full_span = span_start.to(p.prev_token.span);
if !args.options_spans.is_empty() {
let mut err = p
.sess
.span_diagnostic
.struct_span_err(full_span, "clobber_abi is not allowed after options");
err.span_labels(args.options_spans.clone(), "options");
return Err(err);
}
match &new_abis[..] { match &new_abis[..] {
// should have errored above during parsing // should have errored above during parsing
[] => unreachable!(), [] => unreachable!(),
@ -699,6 +668,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
args.operands[idx].1, args.operands[idx].1,
"explicit register arguments cannot be used in the asm template", "explicit register arguments cannot be used in the asm template",
); );
err.span_help(
args.operands[idx].1,
"use the register name directly in the assembly code",
);
} }
err.emit(); err.emit();
None None

View File

@ -290,7 +290,6 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Async(_, _, _) | ExprKind::Async(_, _, _)
| ExprKind::Await(_) | ExprKind::Await(_)
| ExprKind::Block(_, _) | ExprKind::Block(_, _)
| ExprKind::Box(_)
| ExprKind::Break(_, _) | ExprKind::Break(_, _)
| ExprKind::Closure(_) | ExprKind::Closure(_)
| ExprKind::ConstBlock(_) | ExprKind::ConstBlock(_)

View File

@ -42,6 +42,18 @@ pub fn expand_concat(
has_errors = true; has_errors = true;
} }
}, },
// We also want to allow negative numeric literals.
ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => {
match ast::LitKind::from_token_lit(token_lit) {
Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
Err(err) => {
report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
has_errors = true;
}
_ => missing_literal.push(e.span),
}
}
ast::ExprKind::IncludedBytes(..) => { ast::ExprKind::IncludedBytes(..) => {
cx.span_err(e.span, "cannot concatenate a byte string literal") cx.span_err(e.span, "cannot concatenate a byte string literal")
} }
@ -53,9 +65,10 @@ pub fn expand_concat(
} }
} }
} }
if !missing_literal.is_empty() { if !missing_literal.is_empty() {
let mut err = cx.struct_span_err(missing_literal, "expected a literal"); let mut err = cx.struct_span_err(missing_literal, "expected a literal");
err.note("only literals (like `\"foo\"`, `42` and `3.14`) can be passed to `concat!()`"); err.note("only literals (like `\"foo\"`, `-42` and `3.14`) can be passed to `concat!()`");
err.emit(); err.emit();
return DummyResult::any(sp); return DummyResult::any(sp);
} else if has_errors { } else if has_errors {

View File

@ -1052,6 +1052,7 @@ impl<'a> MethodDef<'a> {
/// ::core::hash::Hash::hash(&{ self.y }, state) /// ::core::hash::Hash::hash(&{ self.y }, state)
/// } /// }
/// } /// }
/// ```
fn expand_struct_method_body<'b>( fn expand_struct_method_body<'b>(
&self, &self,
cx: &mut ExtCtxt<'_>, cx: &mut ExtCtxt<'_>,

View File

@ -36,6 +36,21 @@ enum PositionUsedAs {
} }
use PositionUsedAs::*; use PositionUsedAs::*;
struct MacroInput {
fmtstr: P<Expr>,
args: FormatArguments,
/// Whether the first argument was a string literal or a result from eager macro expansion.
/// If it's not a string literal, we disallow implicit arugment capturing.
///
/// This does not correspond to whether we can treat spans to the literal normally, as the whole
/// invocation might be the result of another macro expansion, in which case this flag may still be true.
///
/// See [RFC 2795] for more information.
///
/// [RFC 2795]: https://rust-lang.github.io/rfcs/2795-format-args-implicit-identifiers.html#macro-hygiene
is_direct_literal: bool,
}
/// Parses the arguments from the given list of tokens, returning the diagnostic /// Parses the arguments from the given list of tokens, returning the diagnostic
/// if there's a parse error so we can continue parsing other format! /// if there's a parse error so we can continue parsing other format!
/// expressions. /// expressions.
@ -45,11 +60,7 @@ use PositionUsedAs::*;
/// ```text /// ```text
/// Ok((fmtstr, parsed arguments)) /// Ok((fmtstr, parsed arguments))
/// ``` /// ```
fn parse_args<'a>( fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
ecx: &mut ExtCtxt<'a>,
sp: Span,
tts: TokenStream,
) -> PResult<'a, (P<Expr>, FormatArguments)> {
let mut args = FormatArguments::new(); let mut args = FormatArguments::new();
let mut p = ecx.new_parser_from_tts(tts); let mut p = ecx.new_parser_from_tts(tts);
@ -59,25 +70,21 @@ fn parse_args<'a>(
} }
let first_token = &p.token; let first_token = &p.token;
let fmtstr = match first_token.kind {
token::TokenKind::Literal(token::Lit { let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) {
kind: token::LitKind::Str | token::LitKind::StrRaw(_), // This allows us to properly handle cases when the first comma
.. // after the format string is mistakenly replaced with any operator,
}) => { // which cause the expression parser to eat too much tokens.
// If the first token is a string literal, then a format expression p.parse_literal_maybe_minus()?
// is constructed from it. } else {
// // Otherwise, we fall back to the expression parser.
// This allows us to properly handle cases when the first comma p.parse_expr()?
// after the format string is mistakenly replaced with any operator,
// which cause the expression parser to eat too much tokens.
p.parse_literal_maybe_minus()?
}
_ => {
// Otherwise, we fall back to the expression parser.
p.parse_expr()?
}
}; };
// Only allow implicit captures to be used when the argument is a direct literal
// instead of a macro expanding to one.
let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_));
let mut first = true; let mut first = true;
while p.token != token::Eof { while p.token != token::Eof {
@ -147,17 +154,19 @@ fn parse_args<'a>(
} }
} }
} }
Ok((fmtstr, args)) Ok(MacroInput { fmtstr, args, is_direct_literal })
} }
pub fn make_format_args( fn make_format_args(
ecx: &mut ExtCtxt<'_>, ecx: &mut ExtCtxt<'_>,
efmt: P<Expr>, input: MacroInput,
mut args: FormatArguments,
append_newline: bool, append_newline: bool,
) -> Result<FormatArgs, ()> { ) -> Result<FormatArgs, ()> {
let msg = "format argument must be a string literal"; let msg = "format argument must be a string literal";
let unexpanded_fmt_span = efmt.span; let unexpanded_fmt_span = input.fmtstr.span;
let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) { let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt, msg) {
Ok(mut fmt) if append_newline => { Ok(mut fmt) if append_newline => {
fmt.0 = Symbol::intern(&format!("{}\n", fmt.0)); fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
@ -208,11 +217,11 @@ pub fn make_format_args(
} }
} }
let is_literal = parser.is_literal; let is_source_literal = parser.is_source_literal;
if !parser.errors.is_empty() { if !parser.errors.is_empty() {
let err = parser.errors.remove(0); let err = parser.errors.remove(0);
let sp = if is_literal { let sp = if is_source_literal {
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)) fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
} else { } else {
// The format string could be another macro invocation, e.g.: // The format string could be another macro invocation, e.g.:
@ -230,7 +239,7 @@ pub fn make_format_args(
if let Some(note) = err.note { if let Some(note) = err.note {
e.note(&note); e.note(&note);
} }
if let Some((label, span)) = err.secondary_label && is_literal { if let Some((label, span)) = err.secondary_label && is_source_literal {
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
} }
if err.should_be_replaced_with_positional_argument { if err.should_be_replaced_with_positional_argument {
@ -256,7 +265,7 @@ pub fn make_format_args(
} }
let to_span = |inner_span: rustc_parse_format::InnerSpan| { let to_span = |inner_span: rustc_parse_format::InnerSpan| {
is_literal.then(|| { is_source_literal.then(|| {
fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }) fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
}) })
}; };
@ -304,7 +313,7 @@ pub fn make_format_args(
// Name not found in `args`, so we add it as an implicitly captured argument. // Name not found in `args`, so we add it as an implicitly captured argument.
let span = span.unwrap_or(fmt_span); let span = span.unwrap_or(fmt_span);
let ident = Ident::new(name, span); let ident = Ident::new(name, span);
let expr = if is_literal { let expr = if is_direct_literal {
ecx.expr_ident(span, ident) ecx.expr_ident(span, ident)
} else { } else {
// For the moment capturing variables from format strings expanded from macros is // For the moment capturing variables from format strings expanded from macros is
@ -814,7 +823,7 @@ fn report_invalid_references(
// for `println!("{7:7$}", 1);` // for `println!("{7:7$}", 1);`
indexes.sort(); indexes.sort();
indexes.dedup(); indexes.dedup();
let span: MultiSpan = if !parser.is_literal || parser.arg_places.is_empty() { let span: MultiSpan = if !parser.is_source_literal || parser.arg_places.is_empty() {
MultiSpan::from_span(fmt_span) MultiSpan::from_span(fmt_span)
} else { } else {
MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect())
@ -855,8 +864,8 @@ fn expand_format_args_impl<'cx>(
) -> Box<dyn base::MacResult + 'cx> { ) -> Box<dyn base::MacResult + 'cx> {
sp = ecx.with_def_site_ctxt(sp); sp = ecx.with_def_site_ctxt(sp);
match parse_args(ecx, sp, tts) { match parse_args(ecx, sp, tts) {
Ok((efmt, args)) => { Ok(input) => {
if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) { if let Ok(format_args) = make_format_args(ecx, input, nl) {
MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
} else { } else {
MacEager::expr(DummyResult::raw_expr(sp, true)) MacEager::expr(DummyResult::raw_expr(sp, true))

View File

@ -56,7 +56,7 @@ pub mod proc_macro_harness;
pub mod standard_library_imports; pub mod standard_library_imports;
pub mod test_harness; pub mod test_harness;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
let mut register = |name, kind| resolver.register_builtin_macro(name, kind); let mut register = |name, kind| resolver.register_builtin_macro(name, kind);

View File

@ -1,4 +1,4 @@
#![feature(start, core_intrinsics, alloc_error_handler, box_syntax)] #![feature(start, core_intrinsics, alloc_error_handler)]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
@ -29,7 +29,7 @@ fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
#[start] #[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize { fn main(_argc: isize, _argv: *const *const u8) -> isize {
let world: Box<&str> = box "Hello World!\0"; let world: Box<&str> = Box::new("Hello World!\0");
unsafe { unsafe {
puts(*world as *const str as *const u8); puts(*world as *const str as *const u8);
} }

View File

@ -1,12 +1,6 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // SPDX-License-Identifier: MIT OR Apache-2.0
// file at the top-level directory of this distribution and at // SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![no_std] #![no_std]
pub struct System; pub struct System;

View File

@ -1,4 +1,4 @@
#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)] #![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
#![no_core] #![no_core]
#![allow(dead_code, non_camel_case_types)] #![allow(dead_code, non_camel_case_types)]
@ -178,7 +178,7 @@ fn main() {
let ptr: *const i8 = hello as *const [u8] as *const i8; let ptr: *const i8 = hello as *const [u8] as *const i8;
puts(ptr); puts(ptr);
let world: Box<&str> = box "World!\0"; let world: Box<&str> = Box::new("World!\0");
puts(*world as *const str as *const i8); puts(*world as *const str as *const i8);
world as Box<dyn SomeTrait>; world as Box<dyn SomeTrait>;
@ -238,10 +238,10 @@ fn main() {
} }
} }
let _ = box NoisyDrop { let _ = Box::new(NoisyDrop {
text: "Boxed outer got dropped!\0", text: "Boxed outer got dropped!\0",
inner: NoisyDropInner, inner: NoisyDropInner,
} as Box<dyn SomeTrait>; }) as Box<dyn SomeTrait>;
const FUNC_REF: Option<fn()> = Some(main); const FUNC_REF: Option<fn()> = Some(main);
match FUNC_REF { match FUNC_REF {

View File

@ -4,6 +4,7 @@
use crate::prelude::*; use crate::prelude::*;
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
use rustc_session::config::OomStrategy; use rustc_session::config::OomStrategy;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -13,24 +14,15 @@ pub(crate) fn codegen(
module: &mut impl Module, module: &mut impl Module,
unwind_context: &mut UnwindContext, unwind_context: &mut UnwindContext,
) -> bool { ) -> bool {
let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| { let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
use rustc_middle::middle::dependency_format::Linkage; codegen_inner(
list.iter().any(|&linkage| linkage == Linkage::Dynamic) module,
}); unwind_context,
if any_dynamic_crate { kind,
false tcx.alloc_error_handler_kind(()).unwrap(),
} else if let Some(kind) = tcx.allocator_kind(()) { tcx.sess.opts.unstable_opts.oom,
codegen_inner( );
module, true
unwind_context,
kind,
tcx.alloc_error_handler_kind(()).unwrap(),
tcx.sess.opts.unstable_opts.oom,
);
true
} else {
false
}
} }
fn codegen_inner( fn codegen_inner(

View File

@ -1,4 +1,4 @@
#![feature(start, box_syntax, core_intrinsics, alloc_error_handler, lang_items)] #![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
@ -38,7 +38,7 @@ unsafe extern "C" fn _Unwind_Resume() {
#[start] #[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize { fn main(_argc: isize, _argv: *const *const u8) -> isize {
let world: Box<&str> = box "Hello World!\0"; let world: Box<&str> = Box::new("Hello World!\0");
unsafe { unsafe {
puts(*world as *const str as *const u8); puts(*world as *const str as *const u8);
} }

View File

@ -1,12 +1,6 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // SPDX-License-Identifier: MIT OR Apache-2.0
// file at the top-level directory of this distribution and at // SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![no_std] #![no_std]
#![feature(allocator_api, rustc_private)] #![feature(allocator_api, rustc_private)]
#![cfg_attr(any(unix, target_os = "redox"), feature(libc))] #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]

View File

@ -1,7 +1,7 @@
// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
#![feature( #![feature(
no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage, no_core, unboxed_closures, start, lang_items, never_type, linkage,
extern_types, thread_local extern_types, thread_local
)] )]
#![no_core] #![no_core]
@ -163,7 +163,7 @@ fn main() {
let ptr: *const u8 = hello as *const [u8] as *const u8; let ptr: *const u8 = hello as *const [u8] as *const u8;
puts(ptr); puts(ptr);
let world: Box<&str> = box "World!\0"; let world: Box<&str> = Box::new("World!\0");
puts(*world as *const str as *const u8); puts(*world as *const str as *const u8);
world as Box<dyn SomeTrait>; world as Box<dyn SomeTrait>;
@ -223,10 +223,10 @@ fn main() {
} }
} }
let _ = box NoisyDrop { let _ = Box::new(NoisyDrop {
text: "Boxed outer got dropped!\0", text: "Boxed outer got dropped!\0",
inner: NoisyDropInner, inner: NoisyDropInner,
} as Box<dyn SomeTrait>; }) as Box<dyn SomeTrait>;
const FUNC_REF: Option<fn()> = Some(main); const FUNC_REF: Option<fn()> = Some(main);
#[allow(unreachable_code)] #[allow(unreachable_code)]

View File

@ -1,4 +1,4 @@
#![feature(start, box_syntax, core_intrinsics, lang_items)] #![feature(start, core_intrinsics, lang_items)]
#![no_std] #![no_std]
#[link(name = "c")] #[link(name = "c")]

View File

@ -87,7 +87,7 @@ use rustc_span::Symbol;
use rustc_span::fatal_error::FatalError; use rustc_span::fatal_error::FatalError;
use tempfile::TempDir; use tempfile::TempDir;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub struct PrintOnPanic<F: Fn() -> String>(pub F); pub struct PrintOnPanic<F: Fn() -> String>(pub F);

View File

@ -438,6 +438,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
/// DW_TAG_structure_type (type of variant 1) /// DW_TAG_structure_type (type of variant 1)
/// DW_TAG_structure_type (type of variant 2) /// DW_TAG_structure_type (type of variant 2)
/// DW_TAG_structure_type (type of variant 3) /// DW_TAG_structure_type (type of variant 3)
/// ```
struct VariantMemberInfo<'a, 'll> { struct VariantMemberInfo<'a, 'll> {
variant_index: VariantIdx, variant_index: VariantIdx,
variant_name: Cow<'a, str>, variant_name: Cow<'a, str>,

View File

@ -84,7 +84,7 @@ mod type_of;
mod va_arg; mod va_arg;
mod value; mod value;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
#[derive(Clone)] #[derive(Clone)]
pub struct LlvmCodegenBackend(()); pub struct LlvmCodegenBackend(());

View File

@ -720,6 +720,7 @@ impl<'a> Linker for GccLinker<'a> {
let mut arg = OsString::from("--version-script="); let mut arg = OsString::from("--version-script=");
arg.push(path); arg.push(path);
self.linker_arg(arg); self.linker_arg(arg);
self.linker_arg("--no-undefined-version");
} }
} }
} }

View File

@ -1,3 +1,5 @@
use crate::base::allocator_kind_for_codegen;
use std::collections::hash_map::Entry::*; use std::collections::hash_map::Entry::*;
use rustc_ast::expand::allocator::ALLOCATOR_METHODS; use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
@ -200,7 +202,8 @@ fn exported_symbols_provider_local(
)); ));
} }
if tcx.allocator_kind(()).is_some() { // Mark allocator shim symbols as exported only if they were generated.
if allocator_kind_for_codegen(tcx).is_some() {
for symbol_name in ALLOCATOR_METHODS for symbol_name in ALLOCATOR_METHODS
.iter() .iter()
.map(|method| format!("__rust_{}", method.name)) .map(|method| format!("__rust_{}", method.name))

View File

@ -13,6 +13,7 @@ use crate::mir::place::PlaceRef;
use crate::traits::*; use crate::traits::*;
use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
@ -545,6 +546,23 @@ pub fn collect_debugger_visualizers_transitive(
.collect::<BTreeSet<_>>() .collect::<BTreeSet<_>>()
} }
/// Decide allocator kind to codegen. If `Some(_)` this will be the same as
/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using
/// allocator definitions from a dylib dependency).
pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
// If the crate doesn't have an `allocator_kind` set then there's definitely
// no shim to generate. Otherwise we also check our dependency graph for all
// our output crate types. If anything there looks like its a `Dynamic`
// linkage, then it's already got an allocator shim and we'll be using that
// one instead. If nothing exists then it's our job to generate the
// allocator!
let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
use rustc_middle::middle::dependency_format::Linkage;
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
});
if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
}
pub fn codegen_crate<B: ExtraBackendMethods>( pub fn codegen_crate<B: ExtraBackendMethods>(
backend: B, backend: B,
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
@ -615,20 +633,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
); );
// Codegen an allocator shim, if necessary. // Codegen an allocator shim, if necessary.
// if let Some(kind) = allocator_kind_for_codegen(tcx) {
// If the crate doesn't have an `allocator_kind` set then there's definitely
// no shim to generate. Otherwise we also check our dependency graph for all
// our output crate types. If anything there looks like its a `Dynamic`
// linkage, then it's already got an allocator shim and we'll be using that
// one instead. If nothing exists then it's our job to generate the
// allocator!
let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
use rustc_middle::middle::dependency_format::Linkage;
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
});
let allocator_module = if any_dynamic_crate {
None
} else if let Some(kind) = tcx.allocator_kind(()) {
let llmod_id = let llmod_id =
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string(); cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
let module_llvm = tcx.sess.time("write_allocator_module", || { let module_llvm = tcx.sess.time("write_allocator_module", || {
@ -642,13 +647,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
) )
}); });
Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }) ongoing_codegen.submit_pre_codegened_module_to_llvm(
} else { tcx,
None ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator },
}; );
if let Some(allocator_module) = allocator_module {
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module);
} }
// For better throughput during parallel processing by LLVM, we used to sort // For better throughput during parallel processing by LLVM, we used to sort

View File

@ -247,6 +247,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
// Note that this is also allowed if `actually_rustdoc` so // Note that this is also allowed if `actually_rustdoc` so
// if a target is documenting some wasm-specific code then // if a target is documenting some wasm-specific code then
// it's not spuriously denied. // it's not spuriously denied.
//
// This exception needs to be kept in sync with allowing
// `#[target_feature]` on `main` and `start`.
} else if !tcx.features().target_feature_11 { } else if !tcx.features().target_feature_11 {
let mut err = feature_err( let mut err = feature_err(
&tcx.sess.parse_sess, &tcx.sess.parse_sess,

View File

@ -56,7 +56,7 @@ pub mod mono_item;
pub mod target_features; pub mod target_features;
pub mod traits; pub mod traits;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub struct ModuleCodegen<M> { pub struct ModuleCodegen<M> {
/// The name of the module. When the crate may be saved between /// The name of the module. When the crate may be saved between

View File

@ -241,12 +241,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
// FIXME(eddyb) maybe name the return place as `_0` or `return`?
if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable()
{
return;
}
let vars = match &self.per_local_var_debug_info { let vars = match &self.per_local_var_debug_info {
Some(per_local) => &per_local[local], Some(per_local) => &per_local[local],
None => return, None => return,
@ -303,7 +297,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let local_ref = &self.locals[local]; let local_ref = &self.locals[local];
let name = if bx.sess().fewer_names() { // FIXME Should the return place be named?
let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE {
None None
} else { } else {
Some(match whole_local_var.or(fallback_var.clone()) { Some(match whole_local_var.or(fallback_var.clone()) {

View File

@ -258,6 +258,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// Apply debuginfo to the newly allocated locals. // Apply debuginfo to the newly allocated locals.
fx.debug_introduce_locals(&mut start_bx); fx.debug_introduce_locals(&mut start_bx);
// The builders will be created separately for each basic block at `codegen_block`.
// So drop the builder of `start_llbb` to avoid having two at the same time.
drop(start_bx);
// Codegen the body of each block using reverse postorder // Codegen the body of each block using reverse postorder
for (bb, _) in traversal::reverse_postorder(&mir) { for (bb, _) in traversal::reverse_postorder(&mir) {
fx.codegen_block(bb); fx.codegen_block(bb);

View File

@ -192,7 +192,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("fxsr", None), ("fxsr", None),
("gfni", Some(sym::avx512_target_feature)), ("gfni", Some(sym::avx512_target_feature)),
("lzcnt", None), ("lzcnt", None),
("movbe", Some(sym::movbe_target_feature)), ("movbe", None),
("pclmulqdq", None), ("pclmulqdq", None),
("popcnt", None), ("popcnt", None),
("rdrand", None), ("rdrand", None),
@ -394,7 +394,6 @@ pub fn from_target_feature(
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature, Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
@ -442,7 +441,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
if let DefKind::AssocFn = tcx.def_kind(id) { if let DefKind::AssocFn = tcx.def_kind(id) {
let parent_id = tcx.local_parent(id); let parent_id = tcx.local_parent(id);
if let DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) { if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(
attr_span, attr_span,

View File

@ -536,24 +536,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
local: mir::Local, local: mir::Local,
layout: Option<TyAndLayout<'tcx>>, layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, TyAndLayout<'tcx>> { ) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
// `const_prop` runs into this with an invalid (empty) frame, so we let state = &frame.locals[local];
// have to support that case (mostly by skipping all caching). if let Some(layout) = state.layout.get() {
match frame.locals.get(local).and_then(|state| state.layout.get()) { return Ok(layout);
None => {
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty)
})?;
if let Some(state) = frame.locals.get(local) {
// Layouts of locals are requested a lot, so we cache them.
state.layout.set(Some(layout));
}
Ok(layout)
}
Some(layout) => Ok(layout),
} }
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
self.layout_of(local_ty)
})?;
// Layouts of locals are requested a lot, so we cache them.
state.layout.set(Some(layout));
Ok(layout)
} }
/// Returns the actual dynamic size and alignment of the place at the given type. /// Returns the actual dynamic size and alignment of the place at the given type.

View File

@ -39,7 +39,7 @@ use rustc_macros::fluent_messages;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
const_eval::provide(providers); const_eval::provide(providers);

View File

@ -643,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if base_ty.is_unsafe_ptr() { if base_ty.is_unsafe_ptr() {
if proj_base.is_empty() { if proj_base.is_empty() {
let decl = &self.body.local_decls[place_local]; let decl = &self.body.local_decls[place_local];
if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
let span = decl.source_info.span; let span = decl.source_info.span;
self.check_static(def_id, span); self.check_static(def_id, span);
return; return;
@ -770,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
} }

View File

@ -704,7 +704,7 @@ pub mod ty {
fn importance(&self) -> DiagnosticImportance { fn importance(&self) -> DiagnosticImportance {
match self.0 { match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, mir::LocalKind::Temp => DiagnosticImportance::Secondary,
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
DiagnosticImportance::Primary DiagnosticImportance::Primary
} }

View File

@ -106,8 +106,9 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
// We're only interested in temporaries and the return place // We're only interested in temporaries and the return place
match self.ccx.body.local_kind(index) { match self.ccx.body.local_kind(index) {
LocalKind::Temp | LocalKind::ReturnPointer => {} LocalKind::Arg => return,
LocalKind::Arg | LocalKind::Var => return, LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return,
LocalKind::ReturnPointer | LocalKind::Temp => {}
} }
// Ignore drops, if the temp gets promoted, // Ignore drops, if the temp gets promoted,

View File

@ -64,7 +64,7 @@ use crate::session_diagnostics::{
RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead, RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead,
}; };
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
// tidy-alphabetical-start // tidy-alphabetical-start
@ -331,6 +331,7 @@ fn run_compiler(
if let Some(ppm) = &sess.opts.pretty { if let Some(ppm) = &sess.opts.pretty {
if ppm.needs_ast_map() { if ppm.needs_ast_map() {
queries.global_ctxt()?.enter(|tcx| { queries.global_ctxt()?.enter(|tcx| {
tcx.ensure().early_lint_checks(());
pretty::print_after_hir_lowering(tcx, *ppm); pretty::print_after_hir_lowering(tcx, *ppm);
Ok(()) Ok(())
})?; })?;

View File

@ -5,7 +5,5 @@ the heap at runtime, and therefore cannot be done at compile time.
Erroneous code example: Erroneous code example:
```compile_fail,E0010 ```compile_fail,E0010
#![feature(box_syntax)] const CON : Vec<i32> = vec![1, 2, 3];
const CON : Box<i32> = box 0;
``` ```

View File

@ -41,7 +41,7 @@ impl Add for Foo {
fn main() { fn main() {
let mut x: Foo = Foo(5); let mut x: Foo = Foo(5);
x += Foo(7); // error, `+= cannot be applied to the type `Foo` x += Foo(7); // error, `+=` cannot be applied to the type `Foo`
} }
``` ```

View File

@ -3,14 +3,14 @@ An unknown tool name was found in a scoped lint.
Erroneous code examples: Erroneous code examples:
```compile_fail,E0710 ```compile_fail,E0710
#[allow(clipp::filter_map)] // error!` #[allow(clipp::filter_map)] // error!
fn main() { fn main() {
// business logic // business logic
} }
``` ```
```compile_fail,E0710 ```compile_fail,E0710
#[warn(clipp::filter_map)] // error!` #[warn(clipp::filter_map)] // error!
fn main() { fn main() {
// business logic // business logic
} }

View File

@ -34,7 +34,7 @@ use intl_memoizer::IntlLangMemoizer;
pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue}; pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue};
pub use unic_langid::{langid, LanguageIdentifier}; pub use unic_langid::{langid, LanguageIdentifier};
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>; pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;

View File

@ -76,7 +76,7 @@ pub use snippet::Style;
pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>; pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
pub type PResult<'a, T> = Result<T, PErr<'a>>; pub type PResult<'a, T> = Result<T, PErr<'a>>;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.) // (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)

View File

@ -12,13 +12,13 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{self, Lrc}; use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{ use rustc_errors::{
Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult,
}; };
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics}; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
use rustc_parse::{self, parser, MACRO_ARGUMENTS}; use rustc_parse::{self, parser, MACRO_ARGUMENTS};
use rustc_session::errors::report_lit_error; use rustc_session::errors::report_lit_error;
use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_session::{parse::ParseSess, Limit, Session};
@ -947,14 +947,14 @@ pub trait ResolverExpand {
fn declare_proc_macro(&mut self, id: NodeId); fn declare_proc_macro(&mut self, id: NodeId);
/// Tools registered with `#![register_tool]` and used by tool attributes and lints. /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
fn registered_tools(&self) -> &FxHashSet<Ident>; fn registered_tools(&self) -> &RegisteredTools;
} }
pub trait LintStoreExpand { pub trait LintStoreExpand {
fn pre_expansion_lint( fn pre_expansion_lint(
&self, &self,
sess: &Session, sess: &Session,
registered_tools: &FxHashSet<Ident>, registered_tools: &RegisteredTools,
node_id: NodeId, node_id: NodeId,
attrs: &[Attribute], attrs: &[Attribute],
items: &[P<Item>], items: &[P<Item>],

View File

@ -64,4 +64,4 @@ mod mut_visit {
mod tests; mod tests;
} }
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }

View File

@ -1,12 +1,10 @@
use std::borrow::Cow;
use crate::base::{DummyResult, ExtCtxt, MacResult}; use crate::base::{DummyResult, ExtCtxt, MacResult};
use crate::expand::{parse_ast_fragment, AstFragmentKind}; use crate::expand::{parse_ast_fragment, AstFragmentKind};
use crate::mbe::{ use crate::mbe::{
macro_parser::{MatcherLoc, NamedParseResult, ParseResult::*, TtParser}, macro_parser::{MatcherLoc, NamedParseResult, ParseResult::*, TtParser},
macro_rules::{try_match_macro, Tracker}, macro_rules::{try_match_macro, Tracker},
}; };
use rustc_ast::token::{self, Token}; use rustc_ast::token::{self, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage};
@ -14,6 +12,7 @@ use rustc_parse::parser::{Parser, Recovery};
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::Span; use rustc_span::Span;
use std::borrow::Cow;
use super::macro_rules::{parser_from_cx, NoopTracker}; use super::macro_rules::{parser_from_cx, NoopTracker};
@ -63,6 +62,13 @@ pub(super) fn failed_to_match_macro<'cx>(
err.note(format!("while trying to match {remaining_matcher}")); err.note(format!("while trying to match {remaining_matcher}"));
} }
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
&& (matches!(expected_token.kind, TokenKind::Interpolated(_))
|| matches!(token.kind, TokenKind::Interpolated(_)))
{
err.note("captured metavariables except for `$tt`, `$ident` and `$lifetime` cannot be compared to other tokens");
}
// Check whether there's a missing comma in this macro call, like `println!("{}" a);` // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
if let Some((arg, comma_span)) = arg.add_comma() { if let Some((arg, comma_span)) = arg.add_comma() {
for lhs in lhses { for lhs in lhses {

View File

@ -90,7 +90,7 @@ declare_features! (
(accepted, clone_closures, "1.26.0", Some(44490), None), (accepted, clone_closures, "1.26.0", Some(44490), None),
/// Allows coercing non capturing closures to function pointers. /// Allows coercing non capturing closures to function pointers.
(accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None), (accepted, closure_to_fn_coercion, "1.19.0", Some(39817), None),
/// Allows using `cmpxchg16b` from `core::arch::x86_64`. /// Allows using the CMPXCHG16B target feature.
(accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None), (accepted, cmpxchg16b_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
/// Allows usage of the `compile_error!` macro. /// Allows usage of the `compile_error!` macro.
(accepted, compile_error, "1.20.0", Some(40872), None), (accepted, compile_error, "1.20.0", Some(40872), None),
@ -238,6 +238,8 @@ declare_features! (
(accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None), (accepted, min_const_unsafe_fn, "1.33.0", Some(55607), None),
/// Allows using `Self` and associated types in struct expressions and patterns. /// Allows using `Self` and associated types in struct expressions and patterns.
(accepted, more_struct_aliases, "1.16.0", Some(37544), None), (accepted, more_struct_aliases, "1.16.0", Some(37544), None),
/// Allows using the MOVBE target feature.
(accepted, movbe_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
/// Allows patterns with concurrent by-move and by-ref bindings. /// Allows patterns with concurrent by-move and by-ref bindings.
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
(accepted, move_ref_pattern, "1.49.0", Some(68354), None), (accepted, move_ref_pattern, "1.49.0", Some(68354), None),

View File

@ -200,8 +200,6 @@ declare_features! (
(active, auto_traits, "1.50.0", Some(13231), None), (active, auto_traits, "1.50.0", Some(13231), None),
/// Allows using `box` in patterns (RFC 469). /// Allows using `box` in patterns (RFC 469).
(active, box_patterns, "1.0.0", Some(29641), None), (active, box_patterns, "1.0.0", Some(29641), None),
/// Allows using the `box $expr` syntax.
(active, box_syntax, "1.0.0", Some(49733), None),
/// Allows `#[doc(notable_trait)]`. /// Allows `#[doc(notable_trait)]`.
/// Renamed from `doc_spotlight`. /// Renamed from `doc_spotlight`.
(active, doc_notable_trait, "1.52.0", Some(45040), None), (active, doc_notable_trait, "1.52.0", Some(45040), None),
@ -259,7 +257,6 @@ declare_features! (
(active, ermsb_target_feature, "1.49.0", Some(44839), None), (active, ermsb_target_feature, "1.49.0", Some(44839), None),
(active, hexagon_target_feature, "1.27.0", Some(44839), None), (active, hexagon_target_feature, "1.27.0", Some(44839), None),
(active, mips_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None),
(active, movbe_target_feature, "1.34.0", Some(44839), None),
(active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, powerpc_target_feature, "1.27.0", Some(44839), None),
(active, riscv_target_feature, "1.45.0", Some(44839), None), (active, riscv_target_feature, "1.45.0", Some(44839), None),
(active, rtm_target_feature, "1.35.0", Some(44839), None), (active, rtm_target_feature, "1.35.0", Some(44839), None),

View File

@ -52,6 +52,8 @@ declare_features! (
(removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")), (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
(removed, await_macro, "1.38.0", Some(50547), None, (removed, await_macro, "1.38.0", Some(50547), None,
Some("subsumed by `.await` syntax")), Some("subsumed by `.await` syntax")),
/// Allows using the `box $expr` syntax.
(removed, box_syntax, "CURRENT_RUSTC_VERSION", Some(49733), None, Some("replaced with `#[rustc_box]`")),
/// Allows capturing disjoint fields in a closure/generator (RFC 2229). /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
(removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")), (removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")),
/// Allows comparing raw pointers during const eval. /// Allows comparing raw pointers during const eval.

View File

@ -815,12 +815,13 @@ pub struct ParentedNode<'tcx> {
#[derive(Debug)] #[derive(Debug)]
pub struct AttributeMap<'tcx> { pub struct AttributeMap<'tcx> {
pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>, pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
pub hash: Fingerprint, // Only present when the crate hash is needed.
pub opt_hash: Option<Fingerprint>,
} }
impl<'tcx> AttributeMap<'tcx> { impl<'tcx> AttributeMap<'tcx> {
pub const EMPTY: &'static AttributeMap<'static> = pub const EMPTY: &'static AttributeMap<'static> =
&AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO }; &AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) };
#[inline] #[inline]
pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
@ -832,10 +833,9 @@ impl<'tcx> AttributeMap<'tcx> {
/// These nodes are mapped by `ItemLocalId` alongside the index of their parent node. /// These nodes are mapped by `ItemLocalId` alongside the index of their parent node.
/// The HIR tree, including bodies, is pre-hashed. /// The HIR tree, including bodies, is pre-hashed.
pub struct OwnerNodes<'tcx> { pub struct OwnerNodes<'tcx> {
/// Pre-computed hash of the full HIR. /// Pre-computed hash of the full HIR. Used in the crate hash. Only present
pub hash_including_bodies: Fingerprint, /// when incr. comp. is enabled.
/// Pre-computed hash of the item signature, without recursing into the body. pub opt_hash_including_bodies: Option<Fingerprint>,
pub hash_without_bodies: Fingerprint,
/// Full HIR for the current owner. /// Full HIR for the current owner.
// The zeroth node's parent should never be accessed: the owner's parent is computed by the // The zeroth node's parent should never be accessed: the owner's parent is computed by the
// hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally // hir_owner_parent query. It is set to `ItemLocalId::INVALID` to force an ICE if accidentally
@ -872,8 +872,7 @@ impl fmt::Debug for OwnerNodes<'_> {
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.field("bodies", &self.bodies) .field("bodies", &self.bodies)
.field("hash_without_bodies", &self.hash_without_bodies) .field("opt_hash_including_bodies", &self.opt_hash_including_bodies)
.field("hash_including_bodies", &self.hash_including_bodies)
.finish() .finish()
} }
} }
@ -940,7 +939,8 @@ impl<T> MaybeOwner<T> {
#[derive(Debug)] #[derive(Debug)]
pub struct Crate<'hir> { pub struct Crate<'hir> {
pub owners: IndexVec<LocalDefId, MaybeOwner<&'hir OwnerInfo<'hir>>>, pub owners: IndexVec<LocalDefId, MaybeOwner<&'hir OwnerInfo<'hir>>>,
pub hir_hash: Fingerprint, // Only present when incr. comp. is enabled.
pub opt_hir_hash: Option<Fingerprint>,
} }
#[derive(Debug, HashStable_Generic)] #[derive(Debug, HashStable_Generic)]

View File

@ -296,7 +296,6 @@ language_item_table! {
// FIXME(swatinem): the following lang items are used for async lowering and // FIXME(swatinem): the following lang items are used for async lowering and
// should become obsolete eventually. // should become obsolete eventually.
ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None;
IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None;
GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
Context, sym::Context, context, Target::Struct, GenericRequirement::None; Context, sym::Context, context, Target::Struct, GenericRequirement::None;

View File

@ -100,24 +100,23 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
// `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
// the body satisfies the condition of two nodes being different have different // the body satisfies the condition of two nodes being different have different
// `hash_stable` results. // `hash_stable` results.
let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } = let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self;
*self; opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher);
hash_including_bodies.hash_stable(hcx, hasher);
} }
} }
impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> { impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
// We ignore the `map` since it refers to information included in `hash` which is hashed in // We ignore the `map` since it refers to information included in `opt_hash` which is
// the collector and used for the crate hash. // hashed in the collector and used for the crate hash.
let AttributeMap { hash, map: _ } = *self; let AttributeMap { opt_hash, map: _ } = *self;
hash.hash_stable(hcx, hasher); opt_hash.unwrap().hash_stable(hcx, hasher);
} }
} }
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> { impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
let Crate { owners: _, hir_hash } = self; let Crate { owners: _, opt_hir_hash } = self;
hir_hash.hash_stable(hcx, hasher) opt_hir_hash.unwrap().hash_stable(hcx, hasher)
} }
} }

View File

@ -42,6 +42,9 @@ hir_analysis_assoc_type_binding_not_allowed =
associated type bindings are not allowed here associated type bindings are not allowed here
.label = associated type not allowed here .label = associated type not allowed here
hir_analysis_parenthesized_fn_trait_expansion =
parenthesized trait syntax expands to `{$expanded_type}`
hir_analysis_typeof_reserved_keyword_used = hir_analysis_typeof_reserved_keyword_used =
`typeof` is a reserved keyword but unimplemented `typeof` is a reserved keyword but unimplemented
.suggestion = consider replacing `typeof(...)` with an actual type .suggestion = consider replacing `typeof(...)` with an actual type
@ -125,9 +128,14 @@ hir_analysis_where_clause_on_main = `main` function is not allowed to have a `wh
hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]` hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
.suggestion = remove this annotation .suggestion = remove this annotation
hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]` hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
.label = `start` is not allowed to be `#[track_caller]` .label = `start` is not allowed to be `#[track_caller]`
hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]`
.label = `start` is not allowed to have `#[target_feature]`
hir_analysis_start_not_async = `start` is not allowed to be `async` hir_analysis_start_not_async = `start` is not allowed to be `async`
.label = `start` is not allowed to be `async` .label = `start` is not allowed to be `async`

View File

@ -1,10 +1,14 @@
use crate::astconv::AstConv; use crate::astconv::AstConv;
use crate::errors::{ManualImplementation, MissingTypeParams}; use crate::errors::{
AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
ParenthesizedFnTraitExpansion,
};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::traits::FulfillmentError; use rustc_infer::traits::FulfillmentError;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edit_distance::find_best_match_for_name;
@ -78,43 +82,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Do not suggest the other syntax if we are in trait impl: // Do not suggest the other syntax if we are in trait impl:
// the desugaring would contain an associated type constraint. // the desugaring would contain an associated type constraint.
if !is_impl { if !is_impl {
let args = trait_segment
.args
.as_ref()
.and_then(|args| args.args.get(0))
.and_then(|arg| match arg {
hir::GenericArg::Type(ty) => match ty.kind {
hir::TyKind::Tup(t) => t
.iter()
.map(|e| sess.source_map().span_to_snippet(e.span))
.collect::<Result<Vec<_>, _>>()
.map(|a| a.join(", ")),
_ => sess.source_map().span_to_snippet(ty.span),
}
.map(|s| format!("({})", s))
.ok(),
_ => None,
})
.unwrap_or_else(|| "()".to_string());
let ret = trait_segment
.args()
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { term }) => {
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
};
sess.source_map().span_to_snippet(span).ok()
}
_ => None,
})
.unwrap_or_else(|| "()".to_string());
err.span_suggestion( err.span_suggestion(
span, span,
"use parenthetical notation instead", "use parenthetical notation instead",
format!("{}{} -> {}", trait_segment.ident, args, ret), fn_trait_to_string(self.tcx(), trait_segment, true),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
} }
@ -629,3 +600,69 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.emit(); err.emit();
} }
} }
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_ty_binding(
tcx: TyCtxt<'_>,
span: Span,
segment: Option<(&hir::PathSegment<'_>, Span)>,
) {
tcx.sess.emit_err(AssocTypeBindingNotAllowed { span, fn_trait_expansion: if let Some((segment, span)) = segment && segment.args().parenthesized {
Some(ParenthesizedFnTraitExpansion { span, expanded_type: fn_trait_to_string(tcx, segment, false) })
} else {
None
}});
}
pub(crate) fn fn_trait_to_string(
tcx: TyCtxt<'_>,
trait_segment: &hir::PathSegment<'_>,
parenthesized: bool,
) -> String {
let args = trait_segment
.args
.as_ref()
.and_then(|args| args.args.get(0))
.and_then(|arg| match arg {
hir::GenericArg::Type(ty) => match ty.kind {
hir::TyKind::Tup(t) => t
.iter()
.map(|e| tcx.sess.source_map().span_to_snippet(e.span))
.collect::<Result<Vec<_>, _>>()
.map(|a| a.join(", ")),
_ => tcx.sess.source_map().span_to_snippet(ty.span),
}
.map(|s| {
// `s.empty()` checks to see if the type is the unit tuple, if so we don't want a comma
if parenthesized || s.is_empty() { format!("({})", s) } else { format!("({},)", s) }
})
.ok(),
_ => None,
})
.unwrap_or_else(|| "()".to_string());
let ret = trait_segment
.args()
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
(true, hir::TypeBindingKind::Equality { term }) => {
let span = match term {
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(c) => tcx.hir().span(c.hir_id),
};
(span != tcx.hir().span(trait_segment.hir_id))
.then_some(tcx.sess.source_map().span_to_snippet(span).ok())
.flatten()
}
_ => None,
})
.unwrap_or_else(|| "()".to_string());
if parenthesized {
format!("{}{} -> {}", trait_segment.ident, args, ret)
} else {
format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
}
}

View File

@ -1,9 +1,8 @@
use super::IsMethodCall; use super::IsMethodCall;
use crate::astconv::{ use crate::astconv::{
CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound,
GenericArgCountResult, GenericArgPosition, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition,
}; };
use crate::errors::AssocTypeBindingNotAllowed;
use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd; use rustc_ast::ast::ParamKindOrd;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
@ -433,7 +432,7 @@ pub(crate) fn check_generic_arg_count(
(gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
prohibit_assoc_ty_binding(tcx, b.span); prohibit_assoc_ty_binding(tcx, b.span, None);
} }
let explicit_late_bound = let explicit_late_bound =
@ -589,11 +588,6 @@ pub(crate) fn check_generic_arg_count(
} }
} }
/// Emits an error regarding forbidden type binding associations
pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
}
/// Prohibits explicit lifetime arguments if late-bound lifetime parameters /// Prohibits explicit lifetime arguments if late-bound lifetime parameters
/// are present. This is used both for datatypes and function calls. /// are present. This is used both for datatypes and function calls.
pub(crate) fn prohibit_explicit_late_bound_lifetimes( pub(crate) fn prohibit_explicit_late_bound_lifetimes(

View File

@ -5,9 +5,8 @@
mod errors; mod errors;
pub mod generics; pub mod generics;
use crate::astconv::generics::{ use crate::astconv::errors::prohibit_assoc_ty_binding;
check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding, use crate::astconv::generics::{check_generic_arg_count, create_substs_for_generic_args};
};
use crate::bounds::Bounds; use crate::bounds::Bounds;
use crate::collect::HirPlaceholderCollector; use crate::collect::HirPlaceholderCollector;
use crate::errors::{ use crate::errors::{
@ -295,7 +294,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ty::BoundConstness::NotConst, ty::BoundConstness::NotConst,
); );
if let Some(b) = item_segment.args().bindings.first() { if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span); prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
} }
substs substs
@ -631,7 +630,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
); );
if let Some(b) = item_segment.args().bindings.first() { if let Some(b) = item_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span); prohibit_assoc_ty_binding(self.tcx(), b.span, Some((item_segment, span)));
} }
args args
@ -825,7 +824,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
constness, constness,
); );
if let Some(b) = trait_segment.args().bindings.first() { if let Some(b) = trait_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span); prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span)));
} }
self.tcx().mk_trait_ref(trait_def_id, substs) self.tcx().mk_trait_ref(trait_def_id, substs)
} }
@ -2596,7 +2595,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for segment in segments { for segment in segments {
// Only emit the first error to avoid overloading the user with error messages. // Only emit the first error to avoid overloading the user with error messages.
if let Some(b) = segment.args().bindings.first() { if let Some(b) = segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span); prohibit_assoc_ty_binding(self.tcx(), b.span, None);
return true; return true;
} }
} }
@ -3049,10 +3048,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
} }
&hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => { &hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id); let opaque_ty = tcx.hir().item(item_id);
let def_id = item_id.owner_id.to_def_id();
match opaque_ty.kind { match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
let local_def_id = item_id.owner_id.def_id;
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as
// type a projection.
let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() {
tcx.associated_item_for_impl_trait_in_trait(local_def_id).to_def_id()
} else {
local_def_id.to_def_id()
};
self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait) self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait)
} }
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),

View File

@ -444,7 +444,7 @@ fn check_opaque_meets_bounds<'tcx>(
// version. // version.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
match origin { match origin {
// Checked when type checking the function containing them. // Checked when type checking the function containing them.
@ -1545,6 +1545,6 @@ pub(super) fn check_generator_obligations(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let errors = fulfillment_cx.select_all_or_error(&infcx); let errors = fulfillment_cx.select_all_or_error(&infcx);
debug!(?errors); debug!(?errors);
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
} }

View File

@ -320,7 +320,7 @@ fn compare_method_predicate_entailment<'tcx>(
}); });
} }
CheckImpliedWfMode::Skip => { CheckImpliedWfMode::Skip => {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
return Err(reported); return Err(reported);
} }
} }
@ -720,7 +720,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// RPITs. // RPITs.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
return Err(reported); return Err(reported);
} }
@ -830,7 +830,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Alias(ty::Projection, proj) = ty.kind() if let ty::Alias(ty::Projection, proj) = ty.kind()
&& self.interner().def_kind(proj.def_id) == DefKind::ImplTraitPlaceholder && self.interner().is_impl_trait_in_trait(proj.def_id)
{ {
if let Some((ty, _)) = self.types.get(&proj.def_id) { if let Some((ty, _)) = self.types.get(&proj.def_id) {
return *ty; return *ty;
@ -1731,7 +1731,7 @@ pub(super) fn compare_impl_const_raw(
// version. // version.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None)); return Err(infcx.err_ctxt().report_fulfillment_errors(&errors));
} }
let outlives_environment = OutlivesEnvironment::new(param_env); let outlives_environment = OutlivesEnvironment::new(param_env);
@ -1831,7 +1831,7 @@ fn compare_type_predicate_entailment<'tcx>(
// version. // version.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
return Err(reported); return Err(reported);
} }
@ -1995,13 +1995,20 @@ pub(super) fn check_type_bounds<'tcx>(
let infcx = tcx.infer_ctxt().build(); let infcx = tcx.infer_ctxt().build();
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
let impl_ty_span = match tcx.hir().get_by_def_id(impl_ty_def_id) { // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the
hir::Node::TraitItem(hir::TraitItem { // span for an impl's associated type. Instead, for these, use the def_span for the synthesized
kind: hir::TraitItemKind::Type(_, Some(ty)), // associated type.
.. let impl_ty_span = if tcx.opt_rpitit_info(impl_ty.def_id).is_some() {
}) => ty.span, tcx.def_span(impl_ty_def_id)
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span, } else {
_ => bug!(), match tcx.hir().get_by_def_id(impl_ty_def_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(_, Some(ty)),
..
}) => ty.span,
hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Type(ty), .. }) => ty.span,
_ => bug!(),
}
}; };
let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id); let assumed_wf_types = ocx.assumed_wf_types(param_env, impl_ty_span, impl_ty_def_id);
@ -2044,7 +2051,7 @@ pub(super) fn check_type_bounds<'tcx>(
// version. // version.
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None); let reported = infcx.err_ctxt().report_fulfillment_errors(&errors);
return Err(reported); return Err(reported);
} }

View File

@ -111,7 +111,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>(
let errors = wfcx.select_all_or_error(); let errors = wfcx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
return; return;
} }

View File

@ -345,7 +345,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}), }),
); );
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
// Finally, resolve all regions. // Finally, resolve all regions.
@ -585,7 +585,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]); predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, [source, target]);
let errors = traits::fully_solve_obligation(&infcx, predicate); let errors = traits::fully_solve_obligation(&infcx, predicate);
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
} }
// Finally, resolve all regions. // Finally, resolve all regions.

View File

@ -11,7 +11,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams, TreatProjections};
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -99,7 +99,12 @@ impl<'tcx> InherentCollect<'tcx> {
} }
} }
if let Some(simp) = simplify_type(self.tcx, self_ty, TreatParams::AsInfer) { if let Some(simp) = simplify_type(
self.tcx,
self_ty,
TreatParams::AsCandidateKey,
TreatProjections::AsCandidateKey,
) {
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else { } else {
bug!("unexpected self type: {:?}", self_ty); bug!("unexpected self type: {:?}", self_ty);
@ -159,7 +164,12 @@ impl<'tcx> InherentCollect<'tcx> {
} }
} }
if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsInfer) { if let Some(simp) = simplify_type(
self.tcx,
ty,
TreatParams::AsCandidateKey,
TreatProjections::AsCandidateKey,
) {
self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id);
} else { } else {
bug!("unexpected primitive type: {:?}", ty); bug!("unexpected primitive type: {:?}", ty);

View File

@ -3,7 +3,7 @@ use crate::astconv::AstConv;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_infer::traits::util; use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, ImplTraitInTraitData, Ty, TyCtxt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::Span; use rustc_span::Span;
@ -58,17 +58,10 @@ fn opaque_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
opaque_def_id: DefId, opaque_def_id: DefId,
ast_bounds: &'tcx [hir::GenericBound<'tcx>], ast_bounds: &'tcx [hir::GenericBound<'tcx>],
item_ty: Ty<'tcx>,
span: Span, span: Span,
in_trait: bool,
) -> &'tcx [(ty::Predicate<'tcx>, Span)] { ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
ty::print::with_no_queries!({ ty::print::with_no_queries!({
let substs = InternalSubsts::identity_for_item(tcx, opaque_def_id);
let item_ty = if in_trait {
tcx.mk_projection(opaque_def_id, substs)
} else {
tcx.mk_opaque(opaque_def_id, substs)
};
let icx = ItemCtxt::new(tcx, opaque_def_id); let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds); let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
// Opaque types are implicitly sized unless a `?Sized` bound is found // Opaque types are implicitly sized unless a `?Sized` bound is found
@ -83,7 +76,18 @@ pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
def_id: DefId, def_id: DefId,
) -> &'_ [(ty::Predicate<'_>, Span)] { ) -> &'_ [(ty::Predicate<'_>, Span)] {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); // If the def_id is about an RPITIT, delegate explicit_item_bounds to the opaque_def_id that
// generated the synthesized associate type.
let rpitit_info = if let Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) =
tcx.opt_rpitit_info(def_id)
{
Some(opaque_def_id)
} else {
None
};
let bounds_def_id = rpitit_info.unwrap_or(def_id);
let hir_id = tcx.hir().local_def_id_to_hir_id(bounds_def_id.expect_local());
match tcx.hir().get(hir_id) { match tcx.hir().get(hir_id) {
hir::Node::TraitItem(hir::TraitItem { hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _), kind: hir::TraitItemKind::Type(bounds, _),
@ -94,7 +98,15 @@ pub(super) fn explicit_item_bounds(
kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }), kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }),
span, span,
.. ..
}) => opaque_type_bounds(tcx, def_id, bounds, *span, *in_trait), }) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
let item_ty = if *in_trait || rpitit_info.is_some() {
tcx.mk_projection(def_id, substs)
} else {
tcx.mk_opaque(def_id, substs)
};
opaque_type_bounds(tcx, bounds_def_id, bounds, item_ty, *span)
}
_ => bug!("item_bounds called on {:?}", def_id), _ => bug!("item_bounds called on {:?}", def_id),
} }
} }

View File

@ -9,7 +9,8 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt, self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
}; };
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -244,6 +245,24 @@ fn get_path_containing_arg_in_pat<'hir>(
} }
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> { pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>> {
// If we are computing `type_of` the synthesized associated type for an RPITIT in the impl
// side, use `collect_return_position_impl_trait_in_trait_tys` to infer the value of the
// associated type in the impl.
if let Some(ImplTraitInTraitData::Impl { fn_def_id, .. }) = tcx.opt_rpitit_info(def_id) {
match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
Ok(map) => {
let assoc_item = tcx.associated_item(def_id);
return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]);
}
Err(_) => {
return ty::EarlyBinder(tcx.ty_error_with_message(
DUMMY_SP,
"Could not collect return position impl trait in trait tys",
));
}
}
}
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
use rustc_hir::*; use rustc_hir::*;

View File

@ -129,6 +129,18 @@ pub struct AssocTypeBindingNotAllowed {
#[primary_span] #[primary_span]
#[label] #[label]
pub span: Span, pub span: Span,
#[subdiagnostic]
pub fn_trait_expansion: Option<ParenthesizedFnTraitExpansion>,
}
#[derive(Subdiagnostic)]
#[help(hir_analysis_parenthesized_fn_trait_expansion)]
pub struct ParenthesizedFnTraitExpansion {
#[primary_span]
pub span: Span,
pub expanded_type: String,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -315,6 +327,14 @@ pub(crate) struct TrackCallerOnMain {
pub annotated: Span, pub annotated: Span,
} }
#[derive(Diagnostic)]
#[diag(hir_analysis_target_feature_on_main)]
pub(crate) struct TargetFeatureOnMain {
#[primary_span]
#[label(hir_analysis_target_feature_on_main)]
pub main: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_start_not_track_caller)] #[diag(hir_analysis_start_not_track_caller)]
pub(crate) struct StartTrackCaller { pub(crate) struct StartTrackCaller {
@ -324,6 +344,15 @@ pub(crate) struct StartTrackCaller {
pub start: Span, pub start: Span,
} }
#[derive(Diagnostic)]
#[diag(hir_analysis_start_not_target_feature)]
pub(crate) struct StartTargetFeature {
#[primary_span]
pub span: Span,
#[label]
pub start: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_start_not_async, code = "E0752")] #[diag(hir_analysis_start_not_async, code = "E0752")]
pub(crate) struct StartAsync { pub(crate) struct StartAsync {

View File

@ -174,7 +174,7 @@ fn get_impl_substs(
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None); ocx.infcx.err_ctxt().report_fulfillment_errors(&errors);
return None; return None;
} }

View File

@ -120,7 +120,7 @@ use std::ops::Not;
use astconv::AstConv; use astconv::AstConv;
use bounds::Bounds; use bounds::Bounds;
fluent_messages! { "../locales/en-US.ftl" } fluent_messages! { "../messages.ftl" }
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`"; const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
@ -176,7 +176,7 @@ fn require_same_types<'tcx>(
match &errors[..] { match &errors[..] {
[] => true, [] => true,
errors => { errors => {
infcx.err_ctxt().report_fulfillment_errors(errors, None); infcx.err_ctxt().report_fulfillment_errors(errors);
false false
} }
} }
@ -283,6 +283,15 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true; error = true;
} }
if !tcx.codegen_fn_attrs(main_def_id).target_features.is_empty()
// Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
&& !tcx.sess.target.is_like_wasm
&& !tcx.sess.opts.actually_rustdoc
{
tcx.sess.emit_err(errors::TargetFeatureOnMain { main: main_span });
error = true;
}
if error { if error {
return; return;
} }
@ -309,7 +318,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
ocx.register_bound(cause, param_env, norm_return_ty, term_did); ocx.register_bound(cause, param_env, norm_return_ty, term_did);
let errors = ocx.select_all_or_error(); let errors = ocx.select_all_or_error();
if !errors.is_empty() { if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(&errors, None); infcx.err_ctxt().report_fulfillment_errors(&errors);
error = true; error = true;
} }
// now we can take the return type of the given main function // now we can take the return type of the given main function
@ -373,6 +382,18 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
}); });
error = true; error = true;
} }
if attr.has_name(sym::target_feature)
// Calling functions with `#[target_feature]` is
// not unsafe on WASM, see #84988
&& !tcx.sess.target.is_like_wasm
&& !tcx.sess.opts.actually_rustdoc
{
tcx.sess.emit_err(errors::StartTargetFeature {
span: attr.span,
start: start_span,
});
error = true;
}
} }
if error { if error {

Some files were not shown because too many files have changed in this diff Show More