From 9a7644e17174dff78f94f8b8d81f21379297d1cf Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 11 Sep 2024 12:36:40 -0700 Subject: [PATCH 01/23] rustc_expand: remember module #[path]s during expansion this fixes cycle detection for modules that need a second invocation collection pass after parsing --- compiler/rustc_expand/src/expand.rs | 12 ++++++++++-- compiler/rustc_expand/src/module.rs | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0d56a005f159e..84ae351ed72b6 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -41,7 +41,9 @@ use crate::errors::{ }; use crate::fluent_generated; use crate::mbe::diagnostics::annotate_err_with_kind; -use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; +use crate::module::{ + mod_dir_path, mod_file_path_from_attr, parse_external_mod, DirOwnership, ParsedExternalMod, +}; use crate::placeholders::{placeholder, PlaceholderExpander}; macro_rules! ast_fragments { @@ -1202,8 +1204,14 @@ impl InvocationCollectorNode for P { ecx.current_expansion.dir_ownership, *inline, ); + // If the module was parsed from an external file, recover its path. + // This lets `parse_external_mod` catch cycles if it's self-referential. + let file_path = match inline { + Inline::Yes => None, + Inline::No => mod_file_path_from_attr(ecx.sess, &attrs, &dir_path), + }; node.attrs = attrs; - (None, dir_path, dir_ownership) + (file_path, dir_path, dir_ownership) } ModKind::Unloaded => { // We have an outline `mod foo;` so we need to parse the file. diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 133483768511b..27a9a330f3c5e 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -171,7 +171,7 @@ fn mod_file_path<'a>( /// Derive a submodule path from the first found `#[path = "path_string"]`. /// The provided `dir_path` is joined with the `path_string`. -fn mod_file_path_from_attr( +pub(crate) fn mod_file_path_from_attr( sess: &Session, attrs: &[Attribute], dir_path: &Path, From a187d0a90c939522e563b122dedef2cb7087f8d0 Mon Sep 17 00:00:00 2001 From: dianne Date: Wed, 11 Sep 2024 13:29:25 -0700 Subject: [PATCH 02/23] add regression test for #97589 --- .../circular-module-with-doc-comment-issue-97589.rs | 6 ++++++ .../circular-module-with-doc-comment-issue-97589.stderr | 8 ++++++++ .../recursive.rs | 6 ++++++ 3 files changed, 20 insertions(+) create mode 100644 tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs create mode 100644 tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr create mode 100644 tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs new file mode 100644 index 0000000000000..ff28548b795fc --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.rs @@ -0,0 +1,6 @@ +//@ error-pattern: circular modules +// Regression test for #97589: a doc-comment on a circular module bypassed cycle detection + +#![crate_type = "lib"] + +pub mod recursive; diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr new file mode 100644 index 0000000000000..02d6406775abb --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/circular-module-with-doc-comment-issue-97589.stderr @@ -0,0 +1,8 @@ +error: circular modules: $DIR/recursive.rs -> $DIR/recursive.rs + --> $DIR/recursive.rs:6:1 + | +LL | mod recursive; + | ^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs new file mode 100644 index 0000000000000..3d758be8c0553 --- /dev/null +++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs @@ -0,0 +1,6 @@ +//@ ignore-test: this is an auxiliary file for circular-module-with-doc-comment-issue-97589.rs + +//! this comment caused the circular dependency checker to break + +#[path = "recursive.rs"] +mod recursive; From b94c5a169b588b9d97c014e6dcef18a1acb1f715 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Sun, 25 Aug 2024 02:41:56 -0400 Subject: [PATCH 03/23] Avoid re-validating UTF-8 in `FromUtf8Error::into_utf8_lossy` Refactor `into_utf8_lossy` to copy valid UTF-8 bytes into the buffer, avoiding double validation of bytes. Add tests that mirror the `String::from_utf8_lossy` tests --- library/alloc/src/string.rs | 26 +++++++++++++++++++++++- library/alloc/tests/lib.rs | 1 + library/alloc/tests/string.rs | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 6daab5bc73a9c..837e97dac5c02 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2081,7 +2081,31 @@ impl FromUtf8Error { #[cfg(not(no_global_oom_handling))] #[unstable(feature = "string_from_utf8_lossy_owned", issue = "129436")] pub fn into_utf8_lossy(self) -> String { - String::from_utf8_lossy_owned(self.bytes) + const REPLACEMENT: &str = "\u{FFFD}"; + + let mut res = { + let mut v = Vec::with_capacity(self.bytes.len()); + + // `Utf8Error::valid_up_to` returns the maximum index of validated + // UTF-8 bytes. Copy the valid bytes into the output buffer. + v.extend_from_slice(&self.bytes[..self.error.valid_up_to()]); + + // SAFETY: This is safe because the only bytes present in the buffer + // were validated as UTF-8 by the call to `String::from_utf8` which + // produced this `FromUtf8Error`. + unsafe { String::from_utf8_unchecked(v) } + }; + + let iter = self.bytes[self.error.valid_up_to()..].utf8_chunks(); + + for chunk in iter { + res.push_str(chunk.valid()); + if !chunk.invalid().is_empty() { + res.push_str(REPLACEMENT); + } + } + + res } /// Returns the bytes that were attempted to convert to a `String`. diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index ffc9a233b665d..1d07a7690da43 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -28,6 +28,7 @@ #![feature(iter_next_chunk)] #![feature(round_char_boundary)] #![feature(slice_partition_dedup)] +#![feature(string_from_utf8_lossy_owned)] #![feature(string_remove_matches)] #![feature(const_btree_len)] #![feature(const_trait_impl)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index dc03c4860e84b..d996c55f94660 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -114,6 +114,43 @@ fn test_from_utf8_lossy() { ); } +#[test] +fn test_fromutf8error_into_lossy() { + fn func(input: &[u8]) -> String { + String::from_utf8(input.to_owned()).unwrap_or_else(|e| e.into_utf8_lossy()) + } + + let xs = b"hello"; + let ys = "hello".to_owned(); + assert_eq!(func(xs), ys); + + let xs = "ศไทย中华Việt Nam".as_bytes(); + let ys = "ศไทย中华Việt Nam".to_owned(); + assert_eq!(func(xs), ys); + + let xs = b"Hello\xC2 There\xFF Goodbye"; + assert_eq!(func(xs), "Hello\u{FFFD} There\u{FFFD} Goodbye".to_owned()); + + let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye"; + assert_eq!(func(xs), "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye".to_owned()); + + let xs = b"\xF5foo\xF5\x80bar"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}\u{FFFD}bar".to_owned()); + + let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz".to_owned()); + + let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz"; + assert_eq!(func(xs), "\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz".to_owned()); + + let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar"; + assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar".to_owned()); + + // surrogates + let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar"; + assert_eq!(func(xs), "\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar".to_owned()); +} + #[test] fn test_from_utf16() { let pairs = [ From 6d788a18c5ce42071f7a6fb46e7f280b2ed648d8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 Aug 2024 21:51:00 -0400 Subject: [PATCH 04/23] Resolve RTN for TyKind::Path ending in (..) --- compiler/rustc_resolve/src/late.rs | 33 +++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac03a3ac42c66..2d97834d05a3c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -404,6 +404,8 @@ pub(crate) enum PathSource<'a> { Delegation, /// An arg in a `use<'a, N>` precise-capturing bound. PreciseCapturingArg(Namespace), + // Paths that end with `(..)`, for return type notation. + ReturnTypeNotation, } impl<'a> PathSource<'a> { @@ -413,7 +415,8 @@ impl<'a> PathSource<'a> { PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) - | PathSource::Delegation => ValueNS, + | PathSource::Delegation + | PathSource::ReturnTypeNotation => ValueNS, PathSource::TraitItem(ns) => ns, PathSource::PreciseCapturingArg(ns) => ns, } @@ -425,7 +428,8 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct(..) => true, + | PathSource::TupleStruct(..) + | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::Delegation @@ -471,7 +475,7 @@ impl<'a> PathSource<'a> { }, _ => "value", }, - PathSource::Delegation => "function", + PathSource::ReturnTypeNotation | PathSource::Delegation => "function", PathSource::PreciseCapturingArg(..) => "type or const parameter", } } @@ -540,6 +544,10 @@ impl<'a> PathSource<'a> { Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true, _ => false, }, + PathSource::ReturnTypeNotation => match res { + Res::Def(DefKind::AssocFn, _) => true, + _ => false, + }, PathSource::Delegation => matches!(res, Res::Def(DefKind::Fn | DefKind::AssocFn, _)), PathSource::PreciseCapturingArg(ValueNS) => { matches!(res, Res::Def(DefKind::ConstParam, _)) @@ -565,8 +573,8 @@ impl<'a> PathSource<'a> { (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425, (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532, (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531, - (PathSource::TraitItem(..), true) => E0575, - (PathSource::TraitItem(..), false) => E0576, + (PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575, + (PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, } @@ -781,7 +789,17 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } TyKind::Path(qself, path) => { self.diag_metadata.current_type_path = Some(ty); - self.smart_resolve_path(ty.id, qself, path, PathSource::Type); + + let source = if let Some(seg) = path.segments.last() + && let Some(args) = &seg.args + && matches!(**args, GenericArgs::ParenthesizedElided(..)) + { + PathSource::ReturnTypeNotation + } else { + PathSource::Type + }; + + self.smart_resolve_path(ty.id, qself, path, source); // Check whether we should interpret this as a bare trait object. if qself.is_none() @@ -1920,7 +1938,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type - | PathSource::PreciseCapturingArg(..) => false, + | PathSource::PreciseCapturingArg(..) + | PathSource::ReturnTypeNotation => false, PathSource::Expr(..) | PathSource::Pat | PathSource::Struct From 19881b5a5a17b4fbc91529f867ca4e577af6438a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Aug 2024 14:51:26 -0400 Subject: [PATCH 05/23] Conditionally allow lowering RTN (..) in paths --- compiler/rustc_ast_lowering/src/asm.rs | 5 +- compiler/rustc_ast_lowering/src/delegation.rs | 3 +- compiler/rustc_ast_lowering/src/expr.rs | 7 +- compiler/rustc_ast_lowering/src/lib.rs | 22 ++++++- compiler/rustc_ast_lowering/src/pat.rs | 5 +- compiler/rustc_ast_lowering/src/path.rs | 66 +++++++++++++++++-- compiler/rustc_hir_analysis/messages.ftl | 2 + compiler/rustc_hir_analysis/src/errors.rs | 7 ++ .../src/hir_ty_lowering/mod.rs | 15 ++++- .../return-type-notation/bare-path.rs | 7 +- .../return-type-notation/bare-path.stderr | 37 +++-------- .../let-binding-init-expr-as-ty.rs | 2 +- .../let-binding-init-expr-as-ty.stderr | 17 +++-- 13 files changed, 141 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index a9d1ee5c9c13a..6c966c9f73ac2 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -20,8 +20,8 @@ use super::errors::{ }; use super::LoweringContext; use crate::{ - fluent_generated as fluent, ImplTraitContext, ImplTraitPosition, ParamMode, - ResolverAstLoweringExt, + fluent_generated as fluent, AllowReturnTypeNotation, ImplTraitContext, ImplTraitPosition, + ParamMode, ResolverAstLoweringExt, }; impl<'a, 'hir> LoweringContext<'a, 'hir> { @@ -201,6 +201,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index ac527df474aff..97483e85f77dd 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -52,7 +52,7 @@ use rustc_target::spec::abi; use {rustc_ast as ast, rustc_hir as hir}; use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode}; -use crate::{ImplTraitPosition, ResolverAstLoweringExt}; +use crate::{AllowReturnTypeNotation, ImplTraitPosition, ResolverAstLoweringExt}; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, @@ -340,6 +340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &delegation.qself, &delegation.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e105026ebd19d..974144cc8d99b 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -23,7 +23,7 @@ use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::errors::YieldInClosure; -use crate::{fluent_generated, FnDeclKind, ImplTraitPosition}; +use crate::{fluent_generated, AllowReturnTypeNotation, FnDeclKind, ImplTraitPosition}; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -281,6 +281,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -328,6 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, )), @@ -1291,6 +1293,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1311,6 +1314,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -1336,6 +1340,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efd3ae336afb8..d59197b396a9b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -485,8 +485,16 @@ enum ParamMode { Optional, } +#[derive(Copy, Clone, Debug)] +enum AllowReturnTypeNotation { + Yes, + No, +} + +#[derive(Copy, Clone, Debug)] enum GenericArgsMode { ParenSugar, + ReturnTypeNotation, Err, } @@ -1226,7 +1234,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let id = self.lower_node_id(t.id); - let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None); + let qpath = self.lower_qpath( + t.id, + qself, + path, + param_mode, + // We deny these after the fact in HIR->middle type lowering. + AllowReturnTypeNotation::Yes, + itctx, + None, + ); self.ty_path(id, t.span, qpath) } @@ -2203,6 +2220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &None, &p.path, ParamMode::Explicit, + AllowReturnTypeNotation::No, itctx, Some(modifiers), ) { @@ -2341,6 +2359,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &None, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2419,6 +2438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index d82bdd526b707..584d94ebe2df1 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -11,7 +11,7 @@ use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, }; use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt}; -use crate::ImplTraitPosition; +use crate::{AllowReturnTypeNotation, ImplTraitPosition}; impl<'a, 'hir> LoweringContext<'a, 'hir> { pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> { @@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -55,6 +56,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -66,6 +68,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, + AllowReturnTypeNotation::No, ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 2ab30eff6d864..491c0dfc42e18 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -5,6 +5,7 @@ use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_middle::span_bug; +use rustc_session::parse::add_feature_diagnostics; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, DesugaringKind, Span, Symbol, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; @@ -15,8 +16,8 @@ use super::errors::{ GenericTypeWithParentheses, UseAngleBrackets, }; use super::{ - GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, LoweringContext, ParamMode, - ResolverAstLoweringExt, + AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, + LoweringContext, ParamMode, ResolverAstLoweringExt, }; use crate::ImplTraitPosition; @@ -28,6 +29,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option>, p: &Path, param_mode: ParamMode, + allow_return_type_notation: AllowReturnTypeNotation, itctx: ImplTraitContext, // modifiers of the impl/bound if this is a trait path modifiers: Option, @@ -103,6 +105,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { GenericArgsMode::ParenSugar } + Res::Def(DefKind::AssocFn, _) if i + 1 == proj_start => { + match allow_return_type_notation { + AllowReturnTypeNotation::Yes => GenericArgsMode::ReturnTypeNotation, + AllowReturnTypeNotation::No => GenericArgsMode::Err, + } + } // Avoid duplicated errors. Res::Err => GenericArgsMode::ParenSugar, // An error @@ -164,11 +172,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { + // If this is a type-dependent `T::method(..)`. + let generic_args_mode = if i + 1 == p.segments.len() + && matches!(allow_return_type_notation, AllowReturnTypeNotation::Yes) + { + GenericArgsMode::ReturnTypeNotation + } else { + GenericArgsMode::Err + }; + let hir_segment = self.arena.alloc(self.lower_path_segment( p.span, segment, param_mode, - GenericArgsMode::Err, + generic_args_mode, itctx, None, )); @@ -238,6 +255,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) } GenericArgs::Parenthesized(data) => match generic_args_mode { + GenericArgsMode::ReturnTypeNotation => { + let mut err = if !data.inputs.is_empty() { + self.dcx().create_err(BadReturnTypeNotation::Inputs { + span: data.inputs_span, + }) + } else if let FnRetTy::Ty(ty) = &data.output { + self.dcx().create_err(BadReturnTypeNotation::Output { + span: data.inputs_span.shrink_to_hi().to(ty.span), + }) + } else { + self.dcx().create_err(BadReturnTypeNotation::NeedsDots { + span: data.inputs_span, + }) + }; + if !self.tcx.features().return_type_notation + && self.tcx.sess.is_nightly_build() + { + add_feature_diagnostics( + &mut err, + &self.tcx.sess, + sym::return_type_notation, + ); + } + err.emit(); + ( + GenericArgsCtor { + args: Default::default(), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation, + span: path_span, + }, + false, + ) + } GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data( data, itctx, @@ -279,7 +330,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }, GenericArgs::ParenthesizedElided(span) => { - self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + match generic_args_mode { + GenericArgsMode::ReturnTypeNotation => { + // Ok + } + GenericArgsMode::ParenSugar | GenericArgsMode::Err => { + self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span }); + } + } ( GenericArgsCtor { args: Default::default(), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 633ccacedfcba..f5e8119cdca61 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -48,6 +48,8 @@ hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit wh hir_analysis_bad_precise_capture = expected {$kind} parameter in `use<...>` precise captures list, found {$found} +hir_analysis_bad_return_type_notation_position = return type notation not allowed in this position yet + hir_analysis_cannot_capture_late_bound_const = cannot capture late-bound const parameter in {$what} .label = parameter defined here diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index e4e5f76ae322e..11b6fedf1f935 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1693,3 +1693,10 @@ pub(crate) struct CmseCallGeneric { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_bad_return_type_notation_position)] +pub(crate) struct BadReturnTypeNotation { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7163352e8a439..507446193f749 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,7 +53,7 @@ use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::{debug, debug_span, instrument}; use crate::bounds::Bounds; -use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -1910,6 +1910,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ) } + // Deny any qpath types that were successfully lowered in AST lowering. + Res::Def(DefKind::AssocFn, _) + if let [.., _trait_segment, item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: path.span }); + Ty::new_error(tcx, guar) + } Res::PrimTy(prim_ty) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs index f507d82afec2f..baaa432067bd9 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs @@ -10,17 +10,14 @@ trait Tr { fn foo() where T::method(..): Send, - //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected type, found function + //~^ ERROR expected type, found function ::method(..): Send, //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected associated type, found associated function `Tr::method` { let _ = T::CONST::(..); //~^ ERROR return type notation not allowed in this position yet let _: T::method(..); - //~^ ERROR return type notation not allowed in this position yet - //~| ERROR expected type, found function + //~^ ERROR expected type, found function } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr index cb45de59c7e23..a4305fdf30f4d 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr @@ -1,9 +1,3 @@ -error[E0575]: expected associated type, found associated function `Tr::method` - --> $DIR/bare-path.rs:15:5 - | -LL | ::method(..): Send, - | ^^^^^^^^^^^^^^^^^^^^^ not a associated type - warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bare-path.rs:1:12 | @@ -14,29 +8,11 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:19:23 + --> $DIR/bare-path.rs:17:23 | LL | let _ = T::CONST::(..); | ^^^^ -error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:21:21 - | -LL | let _: T::method(..); - | ^^^^ - -error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:12:14 - | -LL | T::method(..): Send, - | ^^^^ - -error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:15:22 - | -LL | ::method(..): Send, - | ^^^^ - error: expected type, found function --> $DIR/bare-path.rs:12:8 | @@ -49,8 +25,14 @@ note: the associated function is defined here LL | fn method() -> impl Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: return type notation not allowed in this position yet + --> $DIR/bare-path.rs:14:5 + | +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^ + error: expected type, found function - --> $DIR/bare-path.rs:21:15 + --> $DIR/bare-path.rs:19:15 | LL | let _: T::method(..); | ^^^^^^ unexpected function @@ -61,6 +43,5 @@ note: the associated function is defined here LL | fn method() -> impl Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index 06ee421fc3279..fa62f104b8844 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -1,7 +1,7 @@ pub fn foo(num: i32) -> i32 { let foo: i32::from_be(num); //~^ ERROR expected type, found local variable `num` - //~| ERROR parenthesized type parameters may only be used with a `Fn` trait + //~| ERROR argument types not allowed with return type notation //~| ERROR ambiguous associated type foo } diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index b90ae051fb776..03e4882d71f2b 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -6,16 +6,15 @@ LL | let foo: i32::from_be(num); | | | help: use `=` if you meant to assign -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/let-binding-init-expr-as-ty.rs:2:19 +error: argument types not allowed with return type notation + --> $DIR/let-binding-init-expr-as-ty.rs:2:26 | LL | let foo: i32::from_be(num); - | ^^^^^^^^^^^^ only `Fn` traits may use parentheses + | ^^^^^ help: remove the input types: `()` | -help: use angle brackets instead - | -LL | let foo: i32::from_be; - | ~ ~ + = note: see issue #109417 for more information + = help: add `#![feature(return_type_notation)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0223]: ambiguous associated type --> $DIR/let-binding-init-expr-as-ty.rs:2:14 @@ -30,5 +29,5 @@ LL | let foo: ::from_be; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0214, E0223, E0573. -For more information about an error, try `rustc --explain E0214`. +Some errors have detailed explanations: E0223, E0573. +For more information about an error, try `rustc --explain E0223`. From 51b51bb570e076d981e12a8e221ed3a74b3025c6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Aug 2024 15:03:30 -0400 Subject: [PATCH 06/23] Implement RTN in resolve_bound_vars and HIR ty lowering --- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_ast_lowering/src/path.rs | 5 +- .../src/collect/predicates_of.rs | 13 +- .../src/collect/resolve_bound_vars.rs | 109 +++++++ .../src/hir_ty_lowering/bounds.rs | 286 ++++++++++++++---- .../src/hir_ty_lowering/mod.rs | 122 ++++---- compiler/rustc_resolve/src/late.rs | 1 + .../return-type-notation/bare-path.rs | 4 +- .../return-type-notation/bare-path.stderr | 32 +- .../let-binding-init-expr-as-ty.rs | 2 +- .../let-binding-init-expr-as-ty.stderr | 10 +- 11 files changed, 411 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d59197b396a9b..5266eb0e91f3a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -487,11 +487,12 @@ enum ParamMode { #[derive(Copy, Clone, Debug)] enum AllowReturnTypeNotation { + /// Only in types, since RTN is denied later during HIR lowering. Yes, + /// All other positions (path expr, method, use tree). No, } -#[derive(Copy, Clone, Debug)] enum GenericArgsMode { ParenSugar, ReturnTypeNotation, @@ -1239,7 +1240,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, param_mode, - // We deny these after the fact in HIR->middle type lowering. AllowReturnTypeNotation::Yes, itctx, None, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 491c0dfc42e18..6f0641dbc403d 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -16,10 +16,9 @@ use super::errors::{ GenericTypeWithParentheses, UseAngleBrackets, }; use super::{ - AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, LifetimeRes, - LoweringContext, ParamMode, ResolverAstLoweringExt, + AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, + LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt, }; -use crate::ImplTraitPosition; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 7243e85ce98d2..f9539ad0efb5d 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -240,7 +240,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen for predicate in hir_generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { - let ty = icx.lower_ty(bound_pred.bounded_ty); + let ty = icx.lowerer().lower_ty_maybe_return_type_notation(bound_pred.bounded_ty); + let bound_vars = tcx.late_bound_vars(bound_pred.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` @@ -770,6 +771,10 @@ impl<'tcx> ItemCtxt<'tcx> { continue; }; + // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we + // want to only consider predicates with `Self: ...`, but we don't want + // `OnlySelfBounds(true)` since we want to collect the nested associated + // type bound as well. let (only_self_bounds, assoc_name) = match filter { PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => { (OnlySelfBounds(false), None) @@ -780,14 +785,10 @@ impl<'tcx> ItemCtxt<'tcx> { } }; - // Subtle: If we're collecting `SelfAndAssociatedTypeBounds`, then we - // want to only consider predicates with `Self: ...`, but we don't want - // `OnlySelfBounds(true)` since we want to collect the nested associated - // type bound as well. let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) { ty } else if matches!(filter, PredicateFilter::All) { - self.lower_ty(predicate.bounded_ty) + self.lowerer().lower_ty_maybe_return_type_notation(predicate.bounded_ty) } else { continue; }; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 53dcede91c36a..7d8fb39710f46 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -889,7 +889,12 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { (pair, r) }) .unzip(); + self.record_late_bound_vars(hir_id, binders); + + // If this is an RTN type in the self type, then append those to the binder. + self.try_append_return_type_notation_params(hir_id, bounded_ty); + // Even if there are no lifetimes defined here, we still wrap it in a binder // scope. If there happens to be a nested poly trait ref (an error), that // will be `Concatenating` anyways, so we don't have to worry about the depth @@ -1839,6 +1844,110 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let old_value = self.map.defs.swap_remove(&lifetime_ref.hir_id); assert_eq!(old_value, Some(bad_def)); } + + // TODO: + fn try_append_return_type_notation_params( + &mut self, + hir_id: HirId, + hir_ty: &'tcx hir::Ty<'tcx>, + ) { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + // TODO: + return; + }; + + let (mut bound_vars, item_def_id, item_segment) = match qpath { + // TODO: + hir::QPath::Resolved(_, path) + if let [.., item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + let Res::Def(DefKind::AssocFn, item_def_id) = path.res else { + bug!(); + }; + (vec![], item_def_id, item_segment) + } + + // TODO: + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else { + return; + }; + + match path.res { + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => { + let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() + else { + return; + }; + + let one_bound = generics.predicates.iter().find_map(|predicate| { + let hir::WherePredicate::BoundPredicate(predicate) = predicate else { + return None; + }; + let hir::TyKind::Path(hir::QPath::Resolved(None, bounded_path)) = + predicate.bounded_ty.kind + else { + return None; + }; + if bounded_path.res != path.res { + return None; + } + predicate.bounds.iter().find_map(|bound| { + let hir::GenericBound::Trait(trait_, _) = bound else { + return None; + }; + BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_.trait_ref.trait_def_id()?, + item_segment.ident, + ty::AssocKind::Fn, + ) + }) + }); + let Some((bound_vars, assoc_item)) = one_bound else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } + Res::SelfTyAlias { is_trait_impl: true, .. } => todo!(), + _ => return, + } + } + + _ => return, + }; + + // TODO: + bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { + match param.kind { + ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( + ty::BoundRegionKind::BrNamed(param.def_id, param.name), + ), + ty::GenericParamDefKind::Type { .. } => { + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name)) + } + ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, + } + })); + bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); + + // TODO: + let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); + let existing_bound_vars_saved = existing_bound_vars.clone(); + existing_bound_vars.extend(bound_vars); + // TODO: subtle + self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); + } } /// Detects late-bound lifetimes and inserts them into diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index bffe68f9b745f..1aaacf8db3249 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -6,6 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::HirId; use rustc_middle::bug; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -15,6 +16,7 @@ use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, use smallvec::SmallVec; use tracing::{debug, instrument}; +use super::errors::GenericsArgsErrExtend; use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{ @@ -332,74 +334,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .or_insert(constraint.span); let projection_term = if let ty::AssocKind::Fn = assoc_kind { - let mut emitted_bad_param_err = None; - // If we have an method return type bound, then we need to instantiate - // the method's early bound params with suitable late-bound params. - let mut num_bound_vars = candidate.bound_vars().len(); - let args = - candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| { - let arg = match param.kind { - ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( - tcx, - ty::INNERMOST, - ty::BoundRegion { - var: ty::BoundVar::from_usize(num_bound_vars), - kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), - }, - ) - .into(), - ty::GenericParamDefKind::Type { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Type { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - Ty::new_error(tcx, guar).into() - } - ty::GenericParamDefKind::Const { .. } => { - let guar = *emitted_bad_param_err.get_or_insert_with(|| { - self.dcx().emit_err( - crate::errors::ReturnTypeNotationIllegalParam::Const { - span: path_span, - param_span: tcx.def_span(param.def_id), - }, - ) - }); - ty::Const::new_error(tcx, guar).into() - } - }; - num_bound_vars += 1; - arg - }); - - // Next, we need to check that the return-type notation is being used on - // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). - let output = tcx.fn_sig(assoc_item.def_id).skip_binder().output(); - let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() - && tcx.is_impl_trait_in_trait(alias_ty.def_id) - { - alias_ty.into() - } else { - return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { - span: constraint.span, - ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output), - fn_span: tcx.hir().span_if_local(assoc_item.def_id), - note: (), - })); - }; - - // Finally, move the fn return type's bound vars over to account for the early bound - // params (and trait ref's late bound params). This logic is very similar to - // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` - // and it's no coincidence why. - let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); - let bound_vars = tcx.late_bound_vars(constraint.hir_id); - ty::Binder::bind_with_vars(instantiation_output, bound_vars) + ty::Binder::bind_with_vars( + self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(), + bound_vars, + ) } else { // Create the generic arguments for the associated type or constant by joining the // parent arguments (the arguments of the trait) and the own arguments (the ones of @@ -525,6 +464,219 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Ok(()) } + + // TODO: + pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + let hir::TyKind::Path(qpath) = hir_ty.kind else { + return self.lower_ty(hir_ty); + }; + + let tcx = self.tcx(); + match qpath { + hir::QPath::Resolved(opt_self_ty, path) + if let [mod_segments @ .., trait_segment, item_segment] = &path.segments[..] + && item_segment.args.is_some_and(|args| { + matches!( + args.parenthesized, + hir::GenericArgsParentheses::ReturnTypeNotation + ) + }) => + { + let _ = + self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None); + + let Res::Def(DefKind::AssocFn, item_def_id) = path.res else { + bug!(); + }; + let trait_def_id = tcx.parent(item_def_id); + + let Some(self_ty) = opt_self_ty else { + return self.error_missing_qpath_self_ty( + trait_def_id, + hir_ty.span, + item_segment, + ); + }; + let self_ty = self.lower_ty(self_ty); + + let trait_ref = self.lower_mono_trait_ref( + hir_ty.span, + trait_def_id, + self_ty, + trait_segment, + false, + ty::BoundConstness::NotConst, + ); + + let candidate = + ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id)); + + match self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + hir::QPath::TypeRelative(qself, item_segment) + if item_segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + match self + .resolve_type_relative_return_type_notation( + qself, + item_segment, + hir_ty.hir_id, + hir_ty.span, + ) + .and_then(|(candidate, item_def_id)| { + self.lower_return_type_notation_ty(candidate, item_def_id, hir_ty.span) + }) { + Ok(ty) => Ty::new_alias(tcx, ty::Projection, ty), + Err(guar) => Ty::new_error(tcx, guar), + } + } + _ => self.lower_ty(hir_ty), + } + } + + // TODO: + fn resolve_type_relative_return_type_notation( + &self, + qself: &'tcx hir::Ty<'tcx>, + item_segment: &'tcx hir::PathSegment<'tcx>, + qpath_hir_id: HirId, + span: Span, + ) -> Result<(ty::PolyTraitRef<'tcx>, DefId), ErrorGuaranteed> { + let tcx = self.tcx(); + let qself_ty = self.lower_ty(qself); + let assoc_ident = item_segment.ident; + let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind { + path.res + } else { + Res::Err + }; + + let bound = match (qself_ty.kind(), qself_res) { + (_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => { + // `Self` in an impl of a trait -- we have a concrete self type and a + // trait reference. + let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else { + // A cycle error occurred, most likely. + self.dcx().span_bug(span, "expected cycle error"); + }; + + self.probe_single_bound_for_assoc_item( + || { + traits::supertraits( + tcx, + ty::Binder::dummy(trait_ref.instantiate_identity()), + ) + }, + AssocItemQSelf::SelfTyAlias, + ty::AssocKind::Fn, + assoc_ident, + span, + None, + )? + } + ( + &ty::Param(_), + Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), + ) => self.probe_single_ty_param_bound_for_assoc_item( + param_did.expect_local(), + qself.span, + ty::AssocKind::Fn, + assoc_ident, + span, + )?, + _ => todo!(), + }; + + // Don't let `T::method` resolve to some `for<'a> >::method`. + // This is the same restrictions as associated types; even though we could + // support it, it just makes things a lot more difficult to support in + // `resolve_bound_vars`. + if bound.has_bound_vars() { + todo!(); + } + + let trait_def_id = bound.def_id(); + let assoc_ty = self + .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id) + .expect("failed to find associated type"); + + Ok((bound, assoc_ty.def_id)) + } + + // TODO: + fn lower_return_type_notation_ty( + &self, + candidate: ty::PolyTraitRef<'tcx>, + item_def_id: DefId, + path_span: Span, + ) -> Result, ErrorGuaranteed> { + let tcx = self.tcx(); + let mut emitted_bad_param_err = None; + // If we have an method return type bound, then we need to instantiate + // the method's early bound params with suitable late-bound params. + let mut num_bound_vars = candidate.bound_vars().len(); + let args = candidate.skip_binder().args.extend_to(tcx, item_def_id, |param, _| { + let arg = match param.kind { + ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(num_bound_vars), + kind: ty::BoundRegionKind::BrNamed(param.def_id, param.name), + }, + ) + .into(), + ty::GenericParamDefKind::Type { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Type { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + Ty::new_error(tcx, guar).into() + } + ty::GenericParamDefKind::Const { .. } => { + let guar = *emitted_bad_param_err.get_or_insert_with(|| { + self.dcx().emit_err(crate::errors::ReturnTypeNotationIllegalParam::Const { + span: path_span, + param_span: tcx.def_span(param.def_id), + }) + }); + ty::Const::new_error(tcx, guar).into() + } + }; + num_bound_vars += 1; + arg + }); + + // Next, we need to check that the return-type notation is being used on + // an RPITIT (return-position impl trait in trait) or AFIT (async fn in trait). + let output = tcx.fn_sig(item_def_id).skip_binder().output(); + let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind() + && tcx.is_impl_trait_in_trait(alias_ty.def_id) + { + alias_ty + } else { + return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { + span: path_span, + ty: tcx.liberate_late_bound_regions(item_def_id, output), + fn_span: tcx.hir().span_if_local(item_def_id), + note: (), + })); + }; + + // Finally, move the fn return type's bound vars over to account for the early bound + // params (and trait ref's late bound params). This logic is very similar to + // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` + // and it's no coincidence why. + let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); + Ok(ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args)) + } } /// Detect and reject early-bound & escaping late-bound generic params in the type of assoc const bindings. diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 507446193f749..d42a70308d624 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -820,10 +820,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// `ty_param_def_id` is the `LocalDefId` of the type parameter. #[instrument(level = "debug", skip_all, ret)] - fn probe_single_ty_param_bound_for_assoc_ty( + fn probe_single_ty_param_bound_for_assoc_item( &self, ty_param_def_id: LocalDefId, ty_param_span: Span, + kind: ty::AssocKind, assoc_name: Ident, span: Span, ) -> Result, ErrorGuaranteed> { @@ -841,7 +842,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_name) }, AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span), - ty::AssocKind::Type, + kind, assoc_name, span, None, @@ -1081,9 +1082,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ( &ty::Param(_), Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), - ) => self.probe_single_ty_param_bound_for_assoc_ty( + ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, + ty::AssocKind::Type, assoc_ident, span, )?, @@ -1545,48 +1547,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - let path_str = tcx.def_path_str(trait_def_id); - - let def_id = self.item_def_id(); - debug!(item_def_id = ?def_id); - - // FIXME: document why/how this is different from `tcx.local_parent(def_id)` - let parent_def_id = - tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); - debug!(?parent_def_id); - - // If the trait in segment is the same as the trait defining the item, - // use the `` syntax in the error. - let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; - - let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { - vec!["Self".to_string()] - } else { - // Find all the types that have an `impl` for the trait. - tcx.all_impls(trait_def_id) - .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) - .filter(|header| { - // Consider only accessible traits - tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) - && header.polarity != ty::ImplPolarity::Negative - }) - .map(|header| header.trait_ref.instantiate_identity().self_ty()) - // We don't care about blanket impls. - .filter(|self_ty| !self_ty.has_non_region_param()) - .map(|self_ty| tcx.erase_regions(self_ty).to_string()) - .collect() - }; - // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that - // references the trait. Relevant for the first case in - // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - let reported = self.report_ambiguous_assoc_ty( - span, - &type_names, - &[path_str], - item_segment.ident.name, - ); - return Ty::new_error(tcx, reported); + return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment); }; debug!(?self_ty); @@ -1600,6 +1561,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_projection_from_args(tcx, item_def_id, item_args) } + fn error_missing_qpath_self_ty( + &self, + trait_def_id: DefId, + span: Span, + item_segment: &hir::PathSegment<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx(); + let path_str = tcx.def_path_str(trait_def_id); + + let def_id = self.item_def_id(); + debug!(item_def_id = ?def_id); + + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); + debug!(?parent_def_id); + + // If the trait in segment is the same as the trait defining the item, + // use the `` syntax in the error. + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; + + let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { + vec!["Self".to_string()] + } else { + // Find all the types that have an `impl` for the trait. + tcx.all_impls(trait_def_id) + .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) + .filter(|header| { + // Consider only accessible traits + tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) + && header.polarity != ty::ImplPolarity::Negative + }) + .map(|header| header.trait_ref.instantiate_identity().self_ty()) + // We don't care about blanket impls. + .filter(|self_ty| !self_ty.has_non_region_param()) + .map(|self_ty| tcx.erase_regions(self_ty).to_string()) + .collect() + }; + // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that + // references the trait. Relevant for the first case in + // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` + let reported = + self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name); + Ty::new_error(tcx, reported) + } + pub fn prohibit_generic_args<'a>( &self, segments: impl Iterator> + Clone, @@ -1910,19 +1918,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ) } - // Deny any qpath types that were successfully lowered in AST lowering. - Res::Def(DefKind::AssocFn, _) - if let [.., _trait_segment, item_segment] = &path.segments[..] - && item_segment.args.is_some_and(|args| { - matches!( - args.parenthesized, - hir::GenericArgsParentheses::ReturnTypeNotation - ) - }) => - { - let guar = self.dcx().emit_err(BadReturnTypeNotation { span: path.span }); - Ty::new_error(tcx, guar) - } Res::PrimTy(prim_ty) => { assert_eq!(opt_self_ty, None); let _ = self.prohibit_generic_args( @@ -1943,7 +1938,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .tcx() .dcx() .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted"); - Ty::new_error(self.tcx(), e) + Ty::new_error(tcx, e) } Res::Def(..) => { assert_eq!( @@ -2098,6 +2093,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } + // TODO: + hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) + if segment.args.is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); let ty = self.lower_ty(qself); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2d97834d05a3c..813d569710a15 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -790,6 +790,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r TyKind::Path(qself, path) => { self.diag_metadata.current_type_path = Some(ty); + // TODO: let source = if let Some(seg) = path.segments.last() && let Some(args) = &seg.args && matches!(**args, GenericArgs::ParenthesizedElided(..)) diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs index baaa432067bd9..185c05236332b 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.rs @@ -10,14 +10,12 @@ trait Tr { fn foo() where T::method(..): Send, - //~^ ERROR expected type, found function ::method(..): Send, - //~^ ERROR return type notation not allowed in this position yet { let _ = T::CONST::(..); //~^ ERROR return type notation not allowed in this position yet let _: T::method(..); - //~^ ERROR expected type, found function + //~^ ERROR return type notation not allowed in this position yet } fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr index a4305fdf30f4d..dca2bdeab0a7d 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bare-path.stderr @@ -8,40 +8,16 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:17:23 + --> $DIR/bare-path.rs:15:23 | LL | let _ = T::CONST::(..); | ^^^^ -error: expected type, found function - --> $DIR/bare-path.rs:12:8 - | -LL | T::method(..): Send, - | ^^^^^^ unexpected function - | -note: the associated function is defined here - --> $DIR/bare-path.rs:7:5 - | -LL | fn method() -> impl Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: return type notation not allowed in this position yet - --> $DIR/bare-path.rs:14:5 - | -LL | ::method(..): Send, - | ^^^^^^^^^^^^^^^^^^^^^ - -error: expected type, found function - --> $DIR/bare-path.rs:19:15 + --> $DIR/bare-path.rs:17:12 | LL | let _: T::method(..); - | ^^^^^^ unexpected function - | -note: the associated function is defined here - --> $DIR/bare-path.rs:7:5 - | -LL | fn method() -> impl Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs index fa62f104b8844..71e5a0c728d6b 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.rs +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.rs @@ -2,7 +2,7 @@ pub fn foo(num: i32) -> i32 { let foo: i32::from_be(num); //~^ ERROR expected type, found local variable `num` //~| ERROR argument types not allowed with return type notation - //~| ERROR ambiguous associated type + //~| ERROR return type notation not allowed in this position yet foo } diff --git a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr index 03e4882d71f2b..83a5441e3c0c6 100644 --- a/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr +++ b/tests/ui/suggestions/let-binding-init-expr-as-ty.stderr @@ -16,18 +16,12 @@ LL | let foo: i32::from_be(num); = help: add `#![feature(return_type_notation)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0223]: ambiguous associated type +error: return type notation not allowed in this position yet --> $DIR/let-binding-init-expr-as-ty.rs:2:14 | LL | let foo: i32::from_be(num); | ^^^^^^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `from_be` implemented for `i32`, you could use the fully-qualified path - | -LL | let foo: ::from_be; - | ~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 3 previous errors -Some errors have detailed explanations: E0223, E0573. -For more information about an error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0573`. From 7c8e281f735d02cddfd5c5ff350482a19a3d62c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Aug 2024 15:53:39 -0400 Subject: [PATCH 07/23] Flesh out some TODOs --- compiler/rustc_hir_analysis/messages.ftl | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 1 + .../src/collect/resolve_bound_vars.rs | 48 +++++++++++++++---- compiler/rustc_hir_analysis/src/errors.rs | 3 +- .../src/hir_ty_lowering/bounds.rs | 43 ++++++++++++++--- .../src/hir_ty_lowering/mod.rs | 15 +++++- compiler/rustc_resolve/src/late.rs | 4 +- 7 files changed, 97 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index f5e8119cdca61..262277aaa2a47 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -37,7 +37,7 @@ hir_analysis_assoc_kind_mismatch = expected {$expected}, found {$got} hir_analysis_assoc_kind_mismatch_wrap_in_braces_sugg = consider adding braces here -hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters +hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated {$what} of a trait with uninferred generic parameters .suggestion = use a fully qualified path with inferred lifetimes hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index ac9976148e25c..435a0e31b56c2 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -507,6 +507,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { inferred_sugg, bound, mpart_sugg, + what: "type", }), ) } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 7d8fb39710f46..b241f8a5317c4 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1845,19 +1845,38 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { assert_eq!(old_value, Some(bad_def)); } - // TODO: + // When we have a return type notation type in a where clause, like + // `where ::method(..): Send`, we need to introduce new bound + // vars to the existing where clause's binder, to represent the lifetimes + // elided by the return-type-notation syntax. + // + // For example, given + // ``` + // trait Foo { + // async fn x<'r, T>(); + // } + // ``` + // and a bound that looks like: + // `for<'a, 'b> >::x(): Other<'b>` + // this is going to expand to something like: + // `for<'a, 'b, 'r, T> >::x::<'r, T>::{opaque#0}: Other<'b>`. + // + // We handle this similarly for associated-type-bound style return-type-notation + // in `visit_segment_args`. fn try_append_return_type_notation_params( &mut self, hir_id: HirId, hir_ty: &'tcx hir::Ty<'tcx>, ) { let hir::TyKind::Path(qpath) = hir_ty.kind else { - // TODO: + // We only care about path types here. All other self types + // (including nesting the RTN type in another type) don't do + // anything. return; }; let (mut bound_vars, item_def_id, item_segment) = match qpath { - // TODO: + // If we have a fully qualified method, then we don't need to do any special lookup. hir::QPath::Resolved(_, path) if let [.., item_segment] = &path.segments[..] && item_segment.args.is_some_and(|args| { @@ -1873,23 +1892,32 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { (vec![], item_def_id, item_segment) } - // TODO: + // If we have a type-dependent path, then we do need to do some lookup. hir::QPath::TypeRelative(qself, item_segment) if item_segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { + // First, ignore a qself that isn't a type or `Self` param. Those are the + // only ones that support `T::Assoc` anyways in HIR lowering. let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else { return; }; - match path.res { Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { trait_: _ } => { + // Get the generics of this type's hir owner. This is *different* + // from the generics of the parameter's definition, since we want + // to be able to resolve an RTN path on a nested body (e.g. method + // inside an impl) using the where clauses on the method. let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() else { return; }; + // Look for the first bound that contains an associated type that + // matches the segment that we're looking for. We ignore any subsequent + // bounds since we'll be emitting a hard error in HIR lowering, so this + // is purely speculative. let one_bound = generics.predicates.iter().find_map(|predicate| { let hir::WherePredicate::BoundPredicate(predicate) = predicate else { return None; @@ -1927,7 +1955,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { _ => return, }; - // TODO: + // Append the early-bound vars on the function, and then the late-bound ones. + // We actually turn type parameters into higher-ranked types here, but we + // deny them later in HIR lowering. bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| { match param.kind { ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( @@ -1941,11 +1971,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { })); bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars()); - // TODO: + // SUBTLE: Stash the old bound vars onto the *item segment* before appending + // the new bound vars. We do this because we need to know how many bound vars + // are present on the binder explicitly (i.e. not return-type-notation vars) + // to do bound var shifting correctly in HIR lowering. let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); - // TODO: subtle self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 11b6fedf1f935..f332080a71d22 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -787,7 +787,8 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams { pub inferred_sugg: Option, pub bound: String, #[subdiagnostic] - pub mpart_sugg: Option, + pub mpart_sugg: Option, + pub what: &'static str, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 1aaacf8db3249..033334bec8b60 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -465,7 +465,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok(()) } - // TODO: + /// Lower a type, possibly specially handling the type if it's a return type notation + /// which we otherwise deny in other positions. pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { let hir::TyKind::Path(qpath) = hir_ty.kind else { return self.lower_ty(hir_ty); @@ -482,14 +483,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }) => { + // We don't allow generics on the module segments. let _ = self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None); let Res::Def(DefKind::AssocFn, item_def_id) = path.res else { - bug!(); + bug!("expected RTN to resolve to associated fn"); }; let trait_def_id = tcx.parent(item_def_id); + // Good error for `where Trait::method(..): Send`. let Some(self_ty) = opt_self_ty else { return self.error_missing_qpath_self_ty( trait_def_id, @@ -508,6 +511,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::BoundConstness::NotConst, ); + // SUBTLE: As noted at the end of `try_append_return_type_notation_params` + // in `resolve_bound_vars`, we stash the explicit bound vars of the where + // clause onto the item segment of the RTN type. This allows us to know + // how many bound vars are *not* coming from the signature of the function + // from lowering RTN itself. + // + // For example, in `where for<'a> >::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. let candidate = ty::Binder::bind_with_vars(trait_ref, tcx.late_bound_vars(item_segment.hir_id)); @@ -539,7 +554,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // TODO: + /// Perform type-dependent lookup for a *method* for return type notation. + /// This generally mirrors `::lower_assoc_path`. fn resolve_type_relative_return_type_notation( &self, qself: &'tcx hir::Ty<'tcx>, @@ -592,12 +608,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { _ => todo!(), }; - // Don't let `T::method` resolve to some `for<'a> >::method`. + // Don't let `T::method` resolve to some `for<'a> >::method`, + // which may happen via a higher-ranked where clause or supertrait. // This is the same restrictions as associated types; even though we could // support it, it just makes things a lot more difficult to support in - // `resolve_bound_vars`. + // `resolve_bound_vars`, since we'd need to introduce those as elided + // bound vars on the where clause too. if bound.has_bound_vars() { - todo!(); + return Err(self.tcx().dcx().emit_err( + errors::AssociatedItemTraitUninferredGenericParams { + span, + inferred_sugg: Some(span.with_hi(item_segment.ident.span.lo())), + bound: format!("{}::", tcx.anonymize_bound_vars(bound).skip_binder(),), + mpart_sugg: None, + what: "function", + }, + )); } let trait_def_id = bound.def_id(); @@ -608,7 +634,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ok((bound, assoc_ty.def_id)) } - // TODO: + /// Do the common parts of lowering an RTN type. This involves extending the + /// candidate binder to include all of the early- and late-bound vars that are + /// defined on the function itself, and constructing a projection to the RPITIT + /// return type of that function. fn lower_return_type_notation_ty( &self, candidate: ty::PolyTraitRef<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index d42a70308d624..6998f580d808f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2069,6 +2069,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr) } + // If we encounter a fully qualified path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. + hir::TyKind::Path(hir::QPath::Resolved(_, path)) + if path.segments.last().and_then(|segment| segment.args).is_some_and(|args| { + matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) + }) => + { + let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span }); + Ty::new_error(tcx, guar) + } hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => { debug!(?maybe_qself, ?path); let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); @@ -2093,7 +2104,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i), } } - // TODO: + // If we encounter a type relative path with RTN generics, then it must have + // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore + // it's certainly in an illegal position. hir::TyKind::Path(hir::QPath::TypeRelative(_, segment)) if segment.args.is_some_and(|args| { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 813d569710a15..f1d9028f88c10 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -790,7 +790,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r TyKind::Path(qself, path) => { self.diag_metadata.current_type_path = Some(ty); - // TODO: + // If we have a path that ends with `(..)`, then it must be + // return type notation. Resolve that path in the *value* + // namespace. let source = if let Some(seg) = path.segments.last() && let Some(args) = &seg.args && matches!(**args, GenericArgs::ParenthesizedElided(..)) From 174c3f95192068b3d11c00ae77d06808f45c3ef3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Aug 2024 16:31:06 -0400 Subject: [PATCH 08/23] Add missing diagnostics and flesh out tests --- compiler/rustc_ast_lowering/src/lib.rs | 5 ++ compiler/rustc_ast_lowering/src/path.rs | 15 +++--- compiler/rustc_hir_analysis/src/collect.rs | 4 +- .../src/collect/resolve_bound_vars.rs | 9 ++-- compiler/rustc_hir_analysis/src/errors.rs | 4 +- .../src/hir_ty_lowering/bounds.rs | 27 ++++++++-- .../src/hir_ty_lowering/mod.rs | 3 +- .../return-type-notation/path-ambiguous.rs | 27 ++++++++++ .../path-ambiguous.stderr | 54 +++++++++++++++++++ .../path-higher-ranked.rs | 25 +++++++++ .../path-higher-ranked.stderr | 34 ++++++++++++ .../return-type-notation/path-missing.rs | 25 +++++++++ .../return-type-notation/path-missing.stderr | 33 ++++++++++++ .../return-type-notation/path-no-qself.rs | 15 ++++++ .../return-type-notation/path-no-qself.stderr | 23 ++++++++ .../path-non-param-qself.rs | 21 ++++++++ .../path-non-param-qself.stderr | 30 +++++++++++ .../return-type-notation/path-self-qself.rs | 16 ++++++ .../path-self-qself.stderr | 11 ++++ .../return-type-notation/path-type-param.rs | 22 ++++++++ .../path-type-param.stderr | 29 ++++++++++ .../return-type-notation/path-unsatisfied.rs | 25 +++++++++ .../path-unsatisfied.stderr | 36 +++++++++++++ .../return-type-notation/path-works.rs | 23 ++++++++ .../return-type-notation/path-works.stderr | 11 ++++ 25 files changed, 508 insertions(+), 19 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-missing.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-self-qself.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-works.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-works.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5266eb0e91f3a..d13e26d251006 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -494,9 +494,14 @@ enum AllowReturnTypeNotation { } enum GenericArgsMode { + /// Allow paren sugar, don't allow RTN. ParenSugar, + /// Allow RTN, don't allow paren sugar. ReturnTypeNotation, + // Error if parenthesized generics or RTN are encountered. Err, + /// Silence errors when lowering generics. Only used with `Res::Err`. + Silence, } impl<'a, 'hir> LoweringContext<'a, 'hir> { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6f0641dbc403d..03c8097e4c351 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -111,7 +111,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } // Avoid duplicated errors. - Res::Err => GenericArgsMode::ParenSugar, + Res::Err => GenericArgsMode::Silence, // An error _ => GenericArgsMode::Err, }; @@ -288,11 +288,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { false, ) } - GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data( - data, - itctx, - bound_modifier_allowed_features, - ), + GenericArgsMode::ParenSugar | GenericArgsMode::Silence => self + .lower_parenthesized_parameter_data( + data, + itctx, + bound_modifier_allowed_features, + ), GenericArgsMode::Err => { // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait` let sub = if !data.inputs.is_empty() { @@ -330,7 +331,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }, GenericArgs::ParenthesizedElided(span) => { match generic_args_mode { - GenericArgsMode::ReturnTypeNotation => { + GenericArgsMode::ReturnTypeNotation | GenericArgsMode::Silence => { // Ok } GenericArgsMode::ParenSugar | GenericArgsMode::Err => { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 435a0e31b56c2..4c59f7540eebe 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -460,7 +460,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { [] => (generics.span, format!("<{lt_name}>")), [bound, ..] => (bound.span.shrink_to_lo(), format!("{lt_name}, ")), }; - mpart_sugg = Some(errors::AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { + mpart_sugg = Some(errors::AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { fspan: lt_sp, first: sugg, sspan: span.with_hi(item_segment.ident.span.lo()), @@ -502,7 +502,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } Ty::new_error( self.tcx(), - self.tcx().dcx().emit_err(errors::AssociatedTypeTraitUninferredGenericParams { + self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { span, inferred_sugg, bound, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index b241f8a5317c4..3be908fbaea01 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1886,10 +1886,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ) }) => { - let Res::Def(DefKind::AssocFn, item_def_id) = path.res else { - bug!(); - }; - (vec![], item_def_id, item_segment) + match path.res { + Res::Err => return, + Res::Def(DefKind::AssocFn, item_def_id) => (vec![], item_def_id, item_segment), + _ => bug!("only expected method resolution for fully qualified RTN"), + } } // If we have a type-dependent path, then we do need to do some lookup. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f332080a71d22..4edb68e61999e 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -780,7 +780,7 @@ pub(crate) struct PlaceholderNotAllowedItemSignatures { #[derive(Diagnostic)] #[diag(hir_analysis_associated_type_trait_uninferred_generic_params, code = E0212)] -pub(crate) struct AssociatedTypeTraitUninferredGenericParams { +pub(crate) struct AssociatedItemTraitUninferredGenericParams { #[primary_span] pub span: Span, #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = "{bound}")] @@ -796,7 +796,7 @@ pub(crate) struct AssociatedTypeTraitUninferredGenericParams { hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion, applicability = "maybe-incorrect" )] -pub(crate) struct AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion { +pub(crate) struct AssociatedItemTraitUninferredGenericParamsMultipartSuggestion { #[suggestion_part(code = "{first}")] pub fspan: Span, pub first: String, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 033334bec8b60..6f7f312834729 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -487,8 +487,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let _ = self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None); - let Res::Def(DefKind::AssocFn, item_def_id) = path.res else { - bug!("expected RTN to resolve to associated fn"); + let item_def_id = match path.res { + Res::Def(DefKind::AssocFn, item_def_id) => item_def_id, + Res::Err => { + return Ty::new_error_with_message( + tcx, + hir_ty.span, + "failed to resolve RTN", + ); + } + _ => bug!("only expected method resolution for fully qualified RTN"), }; let trait_def_id = tcx.parent(item_def_id); @@ -605,7 +613,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_ident, span, )?, - _ => todo!(), + _ => { + if let Err(reported) = qself_ty.error_reported() { + return Err(reported); + } else { + // FIXME(return_type_notation): Provide some structured suggestion here. + let err = struct_span_code_err!( + self.dcx(), + span, + E0223, + "ambiguous associated function" + ); + return Err(err.emit()); + } + } }; // Don't let `T::method` resolve to some `for<'a> >::method`, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 6998f580d808f..4416caa71ff36 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -813,7 +813,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - /// Search for a trait bound on a type parameter whose trait defines the associated type given by `assoc_name`. + /// Search for a trait bound on a type parameter whose trait defines the associated item + /// given by `assoc_name` and `kind`. /// /// This fails if there is no such bound in the list of candidates or if there are multiple /// candidates in which case it reports ambiguity. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs new file mode 100644 index 0000000000000..cb42c33e364da --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.rs @@ -0,0 +1,27 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait A { + fn method() -> impl Sized; +} +trait B { + fn method() -> impl Sized; +} + +fn ambiguous() +where + T::method(..): Send, + //~^ ERROR ambiguous associated function `method` in bounds of `T` +{ +} + +trait Sub: A + B {} + +fn ambiguous_via_supertrait() +where + T::method(..): Send, + //~^ ERROR ambiguous associated function `method` in bounds of `T` +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr new file mode 100644 index 0000000000000..e841049ac66bd --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-ambiguous.stderr @@ -0,0 +1,54 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-ambiguous.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0221]: ambiguous associated function `method` in bounds of `T` + --> $DIR/path-ambiguous.rs:13:5 + | +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `A` +... +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `B` +... +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ ambiguous associated function `method` + | +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ + +error[E0221]: ambiguous associated function `method` in bounds of `T` + --> $DIR/path-ambiguous.rs:22:5 + | +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `A` +... +LL | fn method() -> impl Sized; + | -------------------------- ambiguous `method` from `B` +... +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ ambiguous associated function `method` + | +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ +help: use fully-qualified syntax to disambiguate + | +LL | ::method(..): Send, + | ~~~~~~~~~~ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0221`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs new file mode 100644 index 0000000000000..a4d8f00537105 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.rs @@ -0,0 +1,25 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait A<'a> { + fn method() -> impl Sized; +} +trait B: for<'a> A<'a> {} + +fn higher_ranked() +where + T: for<'a> A<'a>, + T::method(..): Send, + //~^ ERROR cannot use the associated function of a trait with uninferred generic parameters +{ +} + +fn higher_ranked_via_supertrait() +where + T: B, + T::method(..): Send, + //~^ ERROR cannot use the associated function of a trait with uninferred generic parameters +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr new file mode 100644 index 0000000000000..22de6165503a1 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-higher-ranked.stderr @@ -0,0 +1,34 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-higher-ranked.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0212]: cannot use the associated function of a trait with uninferred generic parameters + --> $DIR/path-higher-ranked.rs:12:5 + | +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | >::method(..): Send, + | ~~~~~~~~~~~~~~ + +error[E0212]: cannot use the associated function of a trait with uninferred generic parameters + --> $DIR/path-higher-ranked.rs:20:5 + | +LL | T::method(..): Send, + | ^^^^^^^^^^^^^ + | +help: use a fully qualified path with inferred lifetimes + | +LL | >::method(..): Send, + | ~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0212`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs new file mode 100644 index 0000000000000..c1a7b95ca2daa --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.rs @@ -0,0 +1,25 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait A { + #[allow(non_camel_case_types)] + type bad; +} + +fn fully_qualified() +where + ::method(..): Send, + //~^ ERROR cannot find method or associated constant `method` in trait `A` + ::bad(..): Send, + //~^ ERROR expected method or associated constant, found associated type `A::bad` +{ +} + +fn type_dependent() +where + T::method(..): Send, + //~^ associated function `method` not found for `T` +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr new file mode 100644 index 0000000000000..0130c3bc61460 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-missing.stderr @@ -0,0 +1,33 @@ +error[E0576]: cannot find method or associated constant `method` in trait `A` + --> $DIR/path-missing.rs:11:15 + | +LL | ::method(..): Send, + | ^^^^^^ not found in `A` + +error[E0575]: expected method or associated constant, found associated type `A::bad` + --> $DIR/path-missing.rs:13:5 + | +LL | ::bad(..): Send, + | ^^^^^^^^^^^^^^^^^ + | + = note: can't use a type alias as a constructor + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-missing.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0220]: associated function `method` not found for `T` + --> $DIR/path-missing.rs:20:8 + | +LL | T::method(..): Send, + | ^^^^^^ associated function `method` not found + +error: aborting due to 3 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0220, E0575, E0576. +For more information about an error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs new file mode 100644 index 0000000000000..d2636789c10ab --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.rs @@ -0,0 +1,15 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait { + fn method() -> impl Sized; +} + +fn test() +where + Trait::method(..): Send, + //~^ ERROR ambiguous associated type +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr new file mode 100644 index 0000000000000..d66b0a109fc17 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-no-qself.stderr @@ -0,0 +1,23 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-no-qself.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0223]: ambiguous associated type + --> $DIR/path-no-qself.rs:10:5 + | +LL | Trait::method(..): Send, + | ^^^^^^^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | ::method: Send, + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs new file mode 100644 index 0000000000000..b0e6ea852b04d --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.rs @@ -0,0 +1,21 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait { + fn method() -> impl Sized; +} + +struct Adt; + +fn non_param_qself() +where + <()>::method(..): Send, + //~^ ERROR ambiguous associated function + i32::method(..): Send, + //~^ ERROR ambiguous associated function + Adt::method(..): Send, + //~^ ERROR ambiguous associated function +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr new file mode 100644 index 0000000000000..cd1aa9813e351 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-non-param-qself.stderr @@ -0,0 +1,30 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-non-param-qself.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:12:5 + | +LL | <()>::method(..): Send, + | ^^^^^^^^^^^^^^^^ + +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:14:5 + | +LL | i32::method(..): Send, + | ^^^^^^^^^^^^^^^ + +error[E0223]: ambiguous associated function + --> $DIR/path-non-param-qself.rs:16:5 + | +LL | Adt::method(..): Send, + | ^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs new file mode 100644 index 0000000000000..1173101ae453a --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs @@ -0,0 +1,16 @@ +//@ check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + fn method() -> impl Sized; +} + +trait Bar: Foo { + fn other() + where + Self::method(..): Send; +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.stderr new file mode 100644 index 0000000000000..ab33647583ca3 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-self-qself.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs new file mode 100644 index 0000000000000..693a300eb1d98 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.rs @@ -0,0 +1,22 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + fn method() -> impl Sized; +} + +fn test() +where + ::method(..): Send, + //~^ ERROR return type notation is not allowed for functions that have type parameters +{ +} + +fn test_type_dependent() +where + ::method(..): Send, + //~^ ERROR return type notation is not allowed for functions that have type parameters +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr new file mode 100644 index 0000000000000..0d33d4f97d7ac --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-type-param.stderr @@ -0,0 +1,29 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-type-param.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation is not allowed for functions that have type parameters + --> $DIR/path-type-param.rs:10:5 + | +LL | fn method() -> impl Sized; + | - type parameter declared here +... +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: return type notation is not allowed for functions that have type parameters + --> $DIR/path-type-param.rs:17:5 + | +LL | fn method() -> impl Sized; + | - type parameter declared here +... +LL | ::method(..): Send, + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs new file mode 100644 index 0000000000000..a5b0b0e4e251c --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.rs @@ -0,0 +1,25 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait { + fn method() -> impl Sized; +} + +struct DoesntWork; +impl Trait for DoesntWork { + fn method() -> impl Sized { + std::ptr::null_mut::<()>() + // This isn't `Send`. + } +} + +fn test() +where + T::method(..): Send, +{ +} + +fn main() { + test::(); + //~^ ERROR `*mut ()` cannot be sent between threads safely +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr new file mode 100644 index 0000000000000..7d32a428555e8 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr @@ -0,0 +1,36 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-unsatisfied.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `*mut ()` cannot be sent between threads safely + --> $DIR/path-unsatisfied.rs:23:12 + | +LL | fn method() -> impl Sized { + | ---------- within this `impl Sized` +... +LL | test::(); + | ^^^^^^^^^^ `*mut ()` cannot be sent between threads safely + | + = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`, which is required by `impl Sized: Send` +note: required because it appears within the type `impl Sized` + --> $DIR/path-unsatisfied.rs:10:20 + | +LL | fn method() -> impl Sized { + | ^^^^^^^^^^ +note: required by a bound in `test` + --> $DIR/path-unsatisfied.rs:18:20 + | +LL | fn test() + | ---- required by a bound in this function +LL | where +LL | T::method(..): Send, + | ^^^^ required by this bound in `test` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-works.rs b/tests/ui/associated-type-bounds/return-type-notation/path-works.rs new file mode 100644 index 0000000000000..027bc89f13e08 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-works.rs @@ -0,0 +1,23 @@ +//@ check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait { + fn method() -> impl Sized; +} + +struct Works; +impl Trait for Works { + fn method() -> impl Sized {} +} + +fn test() +where + T::method(..): Send, +{ +} + +fn main() { + test::(); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-works.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-works.stderr new file mode 100644 index 0000000000000..b1ec8069ba0d4 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-works.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-works.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + From af24d0b66081bebc881769145385f5baeeed390d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 26 Aug 2024 16:39:44 -0400 Subject: [PATCH 09/23] Resolve self type alias in impl for RTN --- .../src/collect/resolve_bound_vars.rs | 26 ++++++++++++++++++- .../path-constrained-in-method.rs | 24 +++++++++++++++++ .../path-constrained-in-method.stderr | 11 ++++++++ .../return-type-notation/path-self-qself.rs | 11 ++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3be908fbaea01..71d9703bb0edc 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1910,6 +1910,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // from the generics of the parameter's definition, since we want // to be able to resolve an RTN path on a nested body (e.g. method // inside an impl) using the where clauses on the method. + // FIXME(return_type_notation): Think of some better way of doing this. let Some(generics) = self.tcx.hir_owner_node(hir_id.owner).generics() else { return; @@ -1948,7 +1949,30 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { }; (bound_vars, assoc_item.def_id, item_segment) } - Res::SelfTyAlias { is_trait_impl: true, .. } => todo!(), + // If we have a self type alias (in an impl), try to resolve an + // associated item from one of the supertraits of the impl's trait. + Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => { + let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self + .tcx + .hir_node_by_def_id(impl_def_id.expect_local()) + .expect_item() + .kind + else { + return; + }; + let Some(trait_def_id) = trait_ref.trait_def_id() else { + return; + }; + let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars( + self.tcx, + trait_def_id, + item_segment.ident, + ty::AssocKind::Fn, + ) else { + return; + }; + (bound_vars, assoc_item.def_id, item_segment) + } _ => return, } } diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs new file mode 100644 index 0000000000000..56abd167fb6b7 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.rs @@ -0,0 +1,24 @@ +//@ check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait { + fn method() -> impl Sized; +} + +fn is_send(_: impl Send) {} + +struct W(T); + +impl W { + fn test() + where + T: Trait, + T::method(..): Send, + { + is_send(T::method()); + } +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.stderr new file mode 100644 index 0000000000000..3db033d8cf5ed --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/path-constrained-in-method.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/path-constrained-in-method.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs index 1173101ae453a..0cf84457ba73f 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/path-self-qself.rs @@ -13,4 +13,15 @@ trait Bar: Foo { Self::method(..): Send; } +fn is_send(_: impl Send) {} + +impl Bar for T { + fn other() + where + Self::method(..): Send, + { + is_send(Self::method()); + } +} + fn main() {} From 50b8915e6d5f9a5829347a6e59ed9e532075343b Mon Sep 17 00:00:00 2001 From: Elli Howard <36134301+qwertynerd97@users.noreply.github.com> Date: Fri, 20 Sep 2024 22:48:36 -0700 Subject: [PATCH 10/23] Add --enable-profiler to armhf dist Adds the --enable-profiler flag to the RUST_CONFIGURE_ARGS for armhf distribution for Linux. This enables running coverage for tests --- src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile index 855465aa38e24..475542b335683 100644 --- a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile @@ -25,5 +25,5 @@ ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ ENV HOSTS=arm-unknown-linux-gnueabihf -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS From b94f2931b30402f8a7284832dd4b4b7d251e82a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Sep 2024 09:17:31 +0200 Subject: [PATCH 11/23] ABI compatibility: mention Result guarantee --- library/core/src/primitive_docs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 5451e45f6c817..962da6643ddb1 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1761,6 +1761,8 @@ mod prim_ref {} /// - `i32` is ABI-compatible with `NonZero`, and similar for all other integer types. /// - If `T` is guaranteed to be subject to the [null pointer /// optimization](option/index.html#representation), then `T` and `Option` are ABI-compatible. +/// Furthermore, if `U` satisfies the requirements [outlined here](result/index.html#representation), +/// then `T` and `Result` and `Result` are all ABI-compatible. /// /// Furthermore, ABI compatibility satisfies the following general properties: /// From 1ddd67a79a77590504ba04f5d9528edf9d319df5 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 15 Aug 2024 09:55:56 +0200 Subject: [PATCH 12/23] add `C-cmse-nonsecure-entry` ABI --- .../rustc_codegen_cranelift/src/abi/mod.rs | 3 +++ compiler/rustc_codegen_llvm/src/abi.rs | 11 ++++++--- compiler/rustc_middle/src/ty/layout.rs | 1 + .../rustc_smir/src/rustc_internal/internal.rs | 1 + .../rustc_smir/src/rustc_smir/convert/abi.rs | 1 + .../rustc_smir/src/rustc_smir/convert/ty.rs | 1 + compiler/rustc_target/src/abi/call/mod.rs | 2 ++ compiler/rustc_target/src/json.rs | 1 + compiler/rustc_target/src/spec/abi/mod.rs | 23 ++++++++++++------- compiler/rustc_target/src/spec/mod.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 1 + compiler/stable_mir/src/abi.rs | 1 + compiler/stable_mir/src/ty.rs | 1 + .../rust-analyzer/crates/hir-ty/src/lib.rs | 3 +++ .../src/completions/extern_abi.rs | 1 + .../crates/intern/src/symbol/symbols.rs | 1 + tests/ui/print-calling-conventions.stdout | 1 + 17 files changed, 43 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 24cf3f061a567..8838b15d29d40 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -61,6 +61,9 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call Conv::CCmseNonSecureCall => { sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented"); } + Conv::CCmseNonSecureEntry => { + sess.dcx().fatal("C-cmse-nonsecure-entry call conv is not yet implemented"); + } Conv::Msp430Intr | Conv::PtxKernel | Conv::AvrInterrupt | Conv::AvrNonBlockingInterrupt => { unreachable!("tried to use {c:?} call conv which only exists on an unsupported target"); diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 26718792f5fa9..0fa8c9d3f1952 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -422,6 +422,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { if let Conv::RiscvInterrupt { kind } = self.conv { func_attrs.push(llvm::CreateAttrStringValue(cx.llcx, "interrupt", kind.as_str())); } + if let Conv::CCmseNonSecureEntry = self.conv { + func_attrs.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")) + } attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &{ func_attrs }); let mut i = 0; @@ -659,9 +662,11 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { impl From for llvm::CallConv { fn from(conv: Conv) -> Self { match conv { - Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { - llvm::CCallConv - } + Conv::C + | Conv::Rust + | Conv::CCmseNonSecureCall + | Conv::CCmseNonSecureEntry + | Conv::RiscvInterrupt { .. } => llvm::CCallConv, Conv::Cold => llvm::ColdCallConv, Conv::PreserveMost => llvm::PreserveMost, Conv::PreserveAll => llvm::PreserveAll, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 877c54c56491e..1becfe2fb8d09 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1191,6 +1191,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option, abi: SpecAbi) -> | RiscvInterruptM | RiscvInterruptS | CCmseNonSecureCall + | CCmseNonSecureEntry | Unadjusted => false, Rust | RustCall | RustCold | RustIntrinsic => { tcx.sess.panic_strategy() == PanicStrategy::Unwind diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index f52cb010a872f..e9c3b3ffc1ddd 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -470,6 +470,7 @@ impl RustcInternal for Abi { Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, + Abi::CCmseNonSecureEntry => rustc_target::spec::abi::Abi::CCmseNonSecureEntry, Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 9f554ec6c3593..06f01aebf9b60 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -105,6 +105,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv { Conv::PreserveAll => CallConvention::PreserveAll, Conv::ArmAapcs => CallConvention::ArmAapcs, Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, + Conv::CCmseNonSecureEntry => CallConvention::CCmseNonSecureEntry, Conv::Msp430Intr => CallConvention::Msp430Intr, Conv::PtxKernel => CallConvention::PtxKernel, Conv::X86Fastcall => CallConvention::X86Fastcall, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index efbb0f244fc8f..74bdf97ac4458 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -910,6 +910,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::spec::abi::Abi { abi::Abi::AvrInterrupt => Abi::AvrInterrupt, abi::Abi::AvrNonBlockingInterrupt => Abi::AvrNonBlockingInterrupt, abi::Abi::CCmseNonSecureCall => Abi::CCmseNonSecureCall, + abi::Abi::CCmseNonSecureEntry => Abi::CCmseNonSecureEntry, abi::Abi::System { unwind } => Abi::System { unwind }, abi::Abi::RustIntrinsic => Abi::RustIntrinsic, abi::Abi::RustCall => Abi::RustCall, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 060ee4a1bc221..f4469467249f4 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -779,6 +779,7 @@ pub enum Conv { // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, + CCmseNonSecureEntry, Msp430Intr, @@ -972,6 +973,7 @@ impl FromStr for Conv { "RustCold" => Ok(Conv::Rust), "ArmAapcs" => Ok(Conv::ArmAapcs), "CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall), + "CCmseNonSecureEntry" => Ok(Conv::CCmseNonSecureEntry), "Msp430Intr" => Ok(Conv::Msp430Intr), "PtxKernel" => Ok(Conv::PtxKernel), "X86Fastcall" => Ok(Conv::X86Fastcall), diff --git a/compiler/rustc_target/src/json.rs b/compiler/rustc_target/src/json.rs index 9436e34d3807d..5fcf5be101fef 100644 --- a/compiler/rustc_target/src/json.rs +++ b/compiler/rustc_target/src/json.rs @@ -103,6 +103,7 @@ impl ToJson for crate::abi::call::Conv { Self::PreserveAll => "PreserveAll", Self::ArmAapcs => "ArmAapcs", Self::CCmseNonSecureCall => "CCmseNonSecureCall", + Self::CCmseNonSecureEntry => "CCmseNonSecureEntry", Self::Msp430Intr => "Msp430Intr", Self::PtxKernel => "PtxKernel", Self::X86Fastcall => "X86Fastcall", diff --git a/compiler/rustc_target/src/spec/abi/mod.rs b/compiler/rustc_target/src/spec/abi/mod.rs index cc383f88fbc5b..cac0cf9959d2e 100644 --- a/compiler/rustc_target/src/spec/abi/mod.rs +++ b/compiler/rustc_target/src/spec/abi/mod.rs @@ -48,6 +48,7 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, + CCmseNonSecureEntry, System { unwind: bool, }, @@ -124,6 +125,7 @@ const AbiDatas: &[AbiData] = &[ AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" }, AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" }, AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" }, + AbiData { abi: Abi::CCmseNonSecureEntry, name: "C-cmse-nonsecure-entry" }, AbiData { abi: Abi::System { unwind: false }, name: "system" }, AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" }, AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" }, @@ -244,6 +246,10 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> { feature: sym::abi_c_cmse_nonsecure_call, explain: "C-cmse-nonsecure-call ABI is experimental and subject to change", }), + "C-cmse-nonsecure-entry" => Err(AbiDisabled::Unstable { + feature: sym::cmse_nonsecure_entry, + explain: "C-cmse-nonsecure-entry ABI is experimental and subject to change", + }), _ => Err(AbiDisabled::Unrecognized), } } @@ -286,15 +292,16 @@ impl Abi { AvrInterrupt => 23, AvrNonBlockingInterrupt => 24, CCmseNonSecureCall => 25, + CCmseNonSecureEntry => 26, // Cross-platform ABIs - System { unwind: false } => 26, - System { unwind: true } => 27, - RustIntrinsic => 28, - RustCall => 29, - Unadjusted => 30, - RustCold => 31, - RiscvInterruptM => 32, - RiscvInterruptS => 33, + System { unwind: false } => 27, + System { unwind: true } => 28, + RustIntrinsic => 29, + RustCall => 30, + Unadjusted => 31, + RustCold => 32, + RiscvInterruptM => 33, + RiscvInterruptS => 34, }; debug_assert!( AbiDatas diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1d478f84c43bb..508baa7da07b0 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2725,6 +2725,7 @@ impl Target { X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), Aapcs { .. } => "arm" == self.arch, CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), + CCmseNonSecureEntry => ["arm", "aarch64"].contains(&&self.arch[..]), Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 2d0c2e83690a6..00d38350b20fc 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -312,6 +312,7 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi, c_variadic: bool) -> Conv { SysV64 { .. } => Conv::X86_64SysV, Aapcs { .. } => Conv::ArmAapcs, CCmseNonSecureCall => Conv::CCmseNonSecureCall, + CCmseNonSecureEntry => Conv::CCmseNonSecureEntry, PtxKernel => Conv::PtxKernel, Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 317bec3050c74..dc73d9c2188af 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -433,6 +433,7 @@ pub enum CallConvention { // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, + CCmseNonSecureEntry, Msp430Intr, diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 5bad3d5ae7a3c..011d19f61430e 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1062,6 +1062,7 @@ pub enum Abi { AvrInterrupt, AvrNonBlockingInterrupt, CCmseNonSecureCall, + CCmseNonSecureEntry, System { unwind: bool }, RustIntrinsic, RustCall, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 2f4e764f4cecf..26ab02558a1bd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -377,6 +377,7 @@ pub enum FnAbi { AvrNonBlockingInterrupt, C, CCmseNonsecureCall, + CCmseNonsecureEntry, CDecl, CDeclUnwind, CUnwind, @@ -434,6 +435,7 @@ impl FnAbi { s if *s == sym::avr_dash_interrupt => FnAbi::AvrInterrupt, s if *s == sym::avr_dash_non_dash_blocking_dash_interrupt => FnAbi::AvrNonBlockingInterrupt, s if *s == sym::C_dash_cmse_dash_nonsecure_dash_call => FnAbi::CCmseNonsecureCall, + s if *s == sym::C_dash_cmse_dash_nonsecure_dash_entry => FnAbi::CCmseNonsecureEntry, s if *s == sym::C_dash_unwind => FnAbi::CUnwind, s if *s == sym::C => FnAbi::C, s if *s == sym::cdecl_dash_unwind => FnAbi::CDeclUnwind, @@ -477,6 +479,7 @@ impl FnAbi { FnAbi::AvrNonBlockingInterrupt => "avr-non-blocking-interrupt", FnAbi::C => "C", FnAbi::CCmseNonsecureCall => "C-cmse-nonsecure-call", + FnAbi::CCmseNonsecureEntry => "C-cmse-nonsecure-entry", FnAbi::CDecl => "C-decl", FnAbi::CDeclUnwind => "cdecl-unwind", FnAbi::CUnwind => "C-unwind", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index 1a06e0a3a0e73..b0e417e6b3351 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -32,6 +32,7 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "riscv-interrupt-m", "riscv-interrupt-s", "C-cmse-nonsecure-call", + "C-cmse-nonsecure-entry", "wasm", "system", "system-unwind", diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 7eb8e4a5e2e52..c066f50489152 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -94,6 +94,7 @@ define_symbols! { avr_dash_interrupt = "avr-interrupt", avr_dash_non_dash_blocking_dash_interrupt = "avr-non-blocking-interrupt", C_dash_cmse_dash_nonsecure_dash_call = "C-cmse-nonsecure-call", + C_dash_cmse_dash_nonsecure_dash_entry = "C-cmse-nonsecure-entry", C_dash_unwind = "C-unwind", cdecl_dash_unwind = "cdecl-unwind", fastcall_dash_unwind = "fastcall-unwind", diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index da67a57f420d7..4415b3c858e35 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -1,5 +1,6 @@ C C-cmse-nonsecure-call +C-cmse-nonsecure-entry C-unwind Rust aapcs From 5722a8078225cff7d420cc6b246706963e707258 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 31 Jul 2024 21:04:06 +0200 Subject: [PATCH 13/23] remove `#[cmse_nonsecure_entry]` --- compiler/rustc_codegen_llvm/src/attributes.rs | 3 --- .../rustc_codegen_ssa/src/codegen_attrs.rs | 18 -------------- .../src/error_codes/E0775.md | 5 ++-- .../src/error_codes/E0776.md | 4 +++- compiler/rustc_error_codes/src/lib.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 4 ---- compiler/rustc_feature/src/unstable.rs | 2 +- .../src/middle/codegen_fn_attrs.rs | 4 +--- compiler/rustc_passes/src/check_attr.rs | 24 ------------------- .../language-features/cmse-nonsecure-entry.md | 8 +++---- src/tools/tidy/src/issues.txt | 1 - .../issue-105594-invalid-attr-validation.rs | 6 ----- ...ssue-105594-invalid-attr-validation.stderr | 21 +++------------- .../cmse-nonsecure-entry/gate_test.rs | 7 +++--- .../cmse-nonsecure-entry/gate_test.stderr | 18 +++++++------- .../cmse-nonsecure-entry/issue-83475.rs | 9 ------- .../cmse-nonsecure-entry/issue-83475.stderr | 11 --------- .../params-on-registers.rs | 12 +++++----- .../cmse-nonsecure-entry/params-on-stack.rs | 17 ++++++++----- .../cmse-nonsecure-entry/trustzone-only.rs | 4 ++-- .../trustzone-only.stderr | 8 +++---- .../cmse-nonsecure-entry/wrong-abi.rs | 16 ------------- .../cmse-nonsecure-entry/wrong-abi.stderr | 9 ------- 23 files changed, 50 insertions(+), 162 deletions(-) delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs delete mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 6df63eec51375..489259da85646 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -483,9 +483,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx); attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]); } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { - to_add.push(llvm::CreateAttrString(cx.llcx, "cmse_nonsecure_entry")); - } if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 137e481f08ccb..9bd8a84f5a3f0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -195,24 +195,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::cmse_nonsecure_entry => { - if let Some(fn_sig) = fn_sig() - && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. }) - { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0776, - "`#[cmse_nonsecure_entry]` requires C ABI" - ) - .emit(); - } - if !tcx.sess.target.llvm_target.contains("thumbv8m") { - struct_span_code_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") - .emit(); - } - codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY - } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { let is_closure = tcx.is_closure_like(did.to_def_id()); diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index 9bafd52f75cf2..beec260e7f131 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -3,11 +3,10 @@ extension. Erroneous code example: -```compile_fail,E0775 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function() {} +pub extern "C-cmse-nonsecure-entry" fn entry_function() {} ``` To fix this error, compile your code for a Rust target that supports the diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md index d65beebe07c61..e46d498d1c262 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0776.md +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` functions require a C ABI Erroneous code example: -```compile_fail,E0776 +```ignore (no longer emitted) #![feature(cmse_nonsecure_entry)] #[no_mangle] diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 11cad0b8f972a..8631de65ec820 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -681,4 +681,5 @@ E0800: 0800, // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. // E0744, // merged into E0728 +// E0776, // Removed; cmse_nonsecure_entry is now `C-cmse-nonsecure-entry` // E0796, // unused error code. We use `static_mut_refs` lint instead. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3b7e0d82d0f62..fa5f152132ad3 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -551,10 +551,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, experimental!(register_tool), ), - gated!( - cmse_nonsecure_entry, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, experimental!(cmse_nonsecure_entry) - ), // RFC 2632 gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 40333c3953a63..edc8e5f075252 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -395,7 +395,7 @@ declare_features! ( (unstable, closure_lifetime_binder, "1.64.0", Some(97362)), /// Allows `#[track_caller]` on closures and coroutines. (unstable, closure_track_caller, "1.57.0", Some(87417)), - /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + /// Allows `extern "C-cmse-nonsecure-entry" fn()`. (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835)), /// Allows `async {}` expressions in const contexts. (unstable, const_async_blocks, "1.53.0", Some(85368)), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index b7d290e58d22b..90dff0f5c7da8 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -120,9 +120,7 @@ bitflags::bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 12; - /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a - /// function as an entry function from Non-Secure code. - const CMSE_NONSECURE_ENTRY = 1 << 13; + // (Bit 13 was used for `#[cmse_nonsecure_entry]`, but is now unused.) // (Bit 14 was used for `#[coverage(off)]`, but is now unused.) /// `#[used(linker)]`: /// indicates that neither LLVM nor the linker will eliminate this function. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2f4dc8abfcd32..841f255dc3a20 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -188,9 +188,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | [sym::rustc_must_implement_one_of, ..] | [sym::rustc_deny_explicit_impl, ..] | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), - [sym::cmse_nonsecure_entry, ..] => { - self.check_cmse_nonsecure_entry(hir_id, attr, span, target) - } [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), @@ -563,27 +560,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition. - fn check_cmse_nonsecure_entry( - &self, - hir_id: HirId, - attr: &Attribute, - span: Span, - target: Target, - ) { - match target { - Target::Fn - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {} - _ => { - self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, - defn_span: span, - on_crate: hir_id == CRATE_HIR_ID, - }); - } - } - } - /// Debugging aid for `object_lifetime_default` query. fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md index 338fbc4b2bfca..ca95ccf33ac26 100644 --- a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -15,10 +15,10 @@ LLVM, the Rust compiler and the linker are providing TrustZone-M feature. One of the things provided, with this unstable feature, is the -`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an +`C-cmse-nonsecure-entry` ABI. This ABI marks a Secure function as an entry function (see [section 5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). -With this attribute, the compiler will do the following: +With this ABI, the compiler will do the following: * add a special symbol on the function which is the `__acle_se_` prefix and the standard function name * constrain the number of parameters to avoid using the Non-Secure stack @@ -38,11 +38,11 @@ gateway veneer. ``` rust,ignore +#![no_std] #![feature(cmse_nonsecure_entry)] #[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(input: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { input + 6 } ``` diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index b2de3457decc1..5edc1973d9d65 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -467,7 +467,6 @@ ui/closures/issue-87814-2.rs ui/closures/issue-90871.rs ui/closures/issue-97607.rs ui/closures/issue-99565.rs -ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs ui/codegen/auxiliary/issue-97708-aux.rs ui/codegen/issue-101585-128bit-repeat.rs ui/codegen/issue-16602-1.rs diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs index bea5faf7253ff..cb196471fd75e 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.rs +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.rs @@ -1,13 +1,7 @@ // This checks that the attribute validation ICE in issue #105594 doesn't // recur. -// -//@ ignore-thumbv8m.base-none-eabi -#![feature(cmse_nonsecure_entry)] fn main() {} #[track_caller] //~ ERROR attribute should be applied to a function static _A: () = (); - -#[cmse_nonsecure_entry] //~ ERROR attribute should be applied to a function -static _B: () = (); //~| ERROR #[cmse_nonsecure_entry]` is only valid for targets diff --git a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr index c6b2d6e78138e..1248967c47b19 100644 --- a/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr +++ b/tests/ui/attributes/issue-105594-invalid-attr-validation.stderr @@ -1,26 +1,11 @@ error[E0739]: attribute should be applied to a function definition - --> $DIR/issue-105594-invalid-attr-validation.rs:9:1 + --> $DIR/issue-105594-invalid-attr-validation.rs:6:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ LL | static _A: () = (); | ------------------- not a function definition -error: attribute should be applied to a function definition - --> $DIR/issue-105594-invalid-attr-validation.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | static _B: () = (); - | ------------------- not a function definition - -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension - --> $DIR/issue-105594-invalid-attr-validation.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0739, E0775. -For more information about an error, try `rustc --explain E0739`. +For more information about this error, try `rustc --explain E0739`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs index 02d5f20febc4a..6061451b2e973 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.rs @@ -1,10 +1,9 @@ // gate-test-cmse_nonsecure_entry #[no_mangle] -#[cmse_nonsecure_entry] -//~^ ERROR [E0775] -//~| ERROR [E0658] -pub extern "C" fn entry_function(input: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + //~^ ERROR [E0570] + //~| ERROR [E0658] input + 6 } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr index beb9716d5906b..dabf16cab3098 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/gate_test.stderr @@ -1,20 +1,20 @@ -error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature - --> $DIR/gate_test.rs:4:1 +error[E0658]: C-cmse-nonsecure-entry ABI is experimental and subject to change + --> $DIR/gate_test.rs:4:12 | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #75835 for more information = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target --> $DIR/gate_test.rs:4:1 | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0775. -For more information about an error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0570, E0658. +For more information about an error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs deleted file mode 100644 index a839406cd0aaf..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Regression test for the ICE described in #83475. - -#![crate_type="lib"] - -#![feature(cmse_nonsecure_entry)] -#[cmse_nonsecure_entry] -//~^ ERROR: attribute should be applied to a function definition -struct XEmpty2; -//~^ NOTE: not a function definition diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr deleted file mode 100644 index 26d3bfe78375b..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: attribute should be applied to a function definition - --> $DIR/issue-83475.rs:6:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct XEmpty2; - | --------------- not a function definition - -error: aborting due to 1 previous error - diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs index e197f94096d1d..de6888fae6235 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-registers.rs @@ -3,14 +3,14 @@ //@ needs-llvm-components: arm #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] -#[lang="sized"] -trait Sized { } -#[lang="copy"] -trait Copy { } +#![crate_type = "lib"] +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} impl Copy for u32 {} #[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { d } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs index e2da3ebb6ae16..4413c461c0444 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/params-on-stack.rs @@ -3,14 +3,19 @@ //@ needs-llvm-components: arm #![feature(cmse_nonsecure_entry, no_core, lang_items)] #![no_core] -#[lang="sized"] -trait Sized { } -#[lang="copy"] -trait Copy { } +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} impl Copy for u32 {} #[no_mangle] -#[cmse_nonsecure_entry] -pub extern "C" fn entry_function(_: u32, _: u32, _: u32, _: u32, e: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function( + _: u32, + _: u32, + _: u32, + _: u32, + e: u32, +) -> u32 { e } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs index 87eccb4fc6e3e..b1275a78ad749 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs @@ -2,8 +2,8 @@ #![feature(cmse_nonsecure_entry)] #[no_mangle] -#[cmse_nonsecure_entry] //~ ERROR [E0775] -pub extern "C" fn entry_function(input: u32) -> u32 { +pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + //~^ ERROR [E0570] input + 6 } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr index 3e6954394f445..77379f7049d02 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr @@ -1,9 +1,9 @@ -error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target --> $DIR/trustzone-only.rs:5:1 | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0775`. +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs deleted file mode 100644 index db4f90e9923cc..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -//@ needs-llvm-components: arm -#![feature(cmse_nonsecure_entry, no_core, lang_items)] -#![no_core] -#[lang = "sized"] -trait Sized {} - -#[lang = "copy"] -trait Copy {} - -#[no_mangle] -#[cmse_nonsecure_entry] -//~^ ERROR `#[cmse_nonsecure_entry]` requires C ABI [E0776] -pub fn entry_function(_: u32, _: u32, _: u32, d: u32) -> u32 { - d -} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr deleted file mode 100644 index c3fae3d8bbb67..0000000000000 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/wrong-abi.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0776]: `#[cmse_nonsecure_entry]` requires C ABI - --> $DIR/wrong-abi.rs:12:1 - | -LL | #[cmse_nonsecure_entry] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0776`. From a33dcb3607ee763616f374eeaa84ddaf41d41ef4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 14:24:49 +0200 Subject: [PATCH 14/23] add test that accepts a `C-cmse-nonsecure-call` function pointer --- .../callback-as-argument.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs new file mode 100644 index 0000000000000..37c8319d98d0a --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/callback-as-argument.rs @@ -0,0 +1,20 @@ +//@ build-pass +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +//@ needs-llvm-components: arm +#![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items, intrinsics)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for u32 {} + +#[no_mangle] +pub extern "C-cmse-nonsecure-entry" fn test( + f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u32, + a: u32, + b: u32, + c: u32, +) -> u32 { + f(a, b, c, 42) +} From a41c209ef30508d58a25dcfe39fb7c7f5f3bf6a2 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 18 Jul 2024 17:13:47 +0200 Subject: [PATCH 15/23] Add assembly test for the cmse unstable features verifies that the correct return instructions are emitted. Co-authored-by: Tamme Dittrich --- tests/assembly/cmse.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/assembly/cmse.rs diff --git a/tests/assembly/cmse.rs b/tests/assembly/cmse.rs new file mode 100644 index 0000000000000..acad77b251357 --- /dev/null +++ b/tests/assembly/cmse.rs @@ -0,0 +1,26 @@ +//@ assembly-output: emit-asm +//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Copt-level=1 +//@ needs-llvm-components: arm +#![crate_type = "lib"] +#![feature(abi_c_cmse_nonsecure_call, cmse_nonsecure_entry, no_core, lang_items)] +#![no_core] +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} + +// CHECK-LABEL: __acle_se_entry_point +// CHECK: bxns +#[no_mangle] +pub extern "C-cmse-nonsecure-entry" fn entry_point() -> i64 { + 0 +} + +// CHECK-LABEL: call_nonsecure +// CHECK: blxns +#[no_mangle] +pub fn call_nonsecure( + f: unsafe extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32) -> u64, +) -> u64 { + unsafe { f(0, 1, 2, 3) } +} From 4d75a4f0f223a5bff18d9e1c43a18929178bf0fc Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 1 Aug 2024 16:30:04 +0200 Subject: [PATCH 16/23] disallow cmse ABIs on unsupported platforms --- compiler/rustc_target/src/spec/mod.rs | 6 ++++-- ...y.stderr => trustzone-only.aarch64.stderr} | 2 +- .../cmse-nonsecure-entry/trustzone-only.rs | 21 ++++++++++++++++--- .../trustzone-only.thumb7.stderr | 9 ++++++++ .../trustzone-only.x86.stderr | 9 ++++++++ 5 files changed, 41 insertions(+), 6 deletions(-) rename tests/ui/cmse-nonsecure/cmse-nonsecure-entry/{trustzone-only.stderr => trustzone-only.aarch64.stderr} (91%) create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr create mode 100644 tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 508baa7da07b0..ec4f5ef79d1f6 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2724,8 +2724,10 @@ impl Target { } X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]), Aapcs { .. } => "arm" == self.arch, - CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]), - CCmseNonSecureEntry => ["arm", "aarch64"].contains(&&self.arch[..]), + CCmseNonSecureCall | CCmseNonSecureEntry => { + ["thumbv8m.main-none-eabi", "thumbv8m.main-none-eabihf", "thumbv8m.base-none-eabi"] + .contains(&&self.llvm_target[..]) + } Win64 { .. } | SysV64 { .. } => self.arch == "x86_64", PtxKernel => self.arch == "nvptx64", Msp430Interrupt => self.arch == "msp430", diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr similarity index 91% rename from tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr rename to tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr index 77379f7049d02..26409279fbeb4 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.aarch64.stderr @@ -1,5 +1,5 @@ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/trustzone-only.rs:5:1 + --> $DIR/trustzone-only.rs:20:1 | LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs index b1275a78ad749..a4ea7a1757d2d 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.rs @@ -1,10 +1,25 @@ -//@ ignore-thumbv8m.main-none-eabi -#![feature(cmse_nonsecure_entry)] +//@ revisions: x86 aarch64 thumb7 +// +//@[x86] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[thumb7] compile-flags: --target thumbv7em-none-eabi +//@[thumb7] needs-llvm-components: arm +#![feature(no_core, lang_items, rustc_attrs, cmse_nonsecure_entry)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for u32 {} #[no_mangle] pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { //~^ ERROR [E0570] - input + 6 + input } fn main() {} diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr new file mode 100644 index 0000000000000..26409279fbeb4 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.thumb7.stderr @@ -0,0 +1,9 @@ +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:20:1 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr new file mode 100644 index 0000000000000..26409279fbeb4 --- /dev/null +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/trustzone-only.x86.stderr @@ -0,0 +1,9 @@ +error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target + --> $DIR/trustzone-only.rs:20:1 + | +LL | pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0570`. From ac9a49f62d6c1cc777a2dde6d48699692b8eb2c5 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sat, 21 Sep 2024 13:09:09 +0200 Subject: [PATCH 17/23] mark `E0775` as no longer emitte by the compiler --- compiler/rustc_error_codes/src/error_codes/E0775.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md index beec260e7f131..efbd51e89ea3a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0775.md +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension. From 1de894f0c1882aed5b6fba6b665de7664626bd59 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Sep 2024 22:59:03 -0400 Subject: [PATCH 18/23] More tests and tweak comments --- .../src/collect/resolve_bound_vars.rs | 19 +++++-- .../bad-inputs-and-output.rs | 18 +++++++ .../bad-inputs-and-output.stderr | 39 +++++++++++++- .../higher-ranked-bound-works.rs | 52 +++++++++++++++++++ .../higher-ranked-bound-works.stderr | 11 ++++ .../namespace-conflict.rs | 42 +++++++++++++++ .../namespace-conflict.stderr | 11 ++++ .../return-type-notation/non-rpitit.rs | 7 ++- .../return-type-notation/non-rpitit.stderr | 19 +++++-- .../return-type-notation/not-a-method.rs | 42 +++++++++++++++ .../return-type-notation/not-a-method.stderr | 49 +++++++++++++++++ 11 files changed, 298 insertions(+), 11 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr create mode 100644 tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs create mode 100644 tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 71d9703bb0edc..d1601446b6f4c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1640,9 +1640,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // } // ``` // and a bound that looks like: - // `for<'a> T::Trait<'a, x(): for<'b> Other<'b>>` + // `for<'a> T::Trait<'a, x(..): for<'b> Other<'b>>` // this is going to expand to something like: - // `for<'a> for<'r, T> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. + // `for<'a> for<'r> >::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`. if constraint.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id @@ -1853,13 +1853,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // For example, given // ``` // trait Foo { - // async fn x<'r, T>(); + // async fn x<'r>(); // } // ``` // and a bound that looks like: // `for<'a, 'b> >::x(): Other<'b>` // this is going to expand to something like: - // `for<'a, 'b, 'r, T> >::x::<'r, T>::{opaque#0}: Other<'b>`. + // `for<'a, 'b, 'r> >::x::<'r, T>::{opaque#0}: Other<'b>`. // // We handle this similarly for associated-type-bound style return-type-notation // in `visit_segment_args`. @@ -2000,6 +2000,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // the new bound vars. We do this because we need to know how many bound vars // are present on the binder explicitly (i.e. not return-type-notation vars) // to do bound var shifting correctly in HIR lowering. + // + // For example, in `where for<'a> >::method(..): Other`, + // the `late_bound_vars` of the where clause predicate (i.e. this HIR ty's + // parent) will include `'a` AND all the early- and late-bound vars of the + // method. But when lowering the RTN type, we just want the list of vars + // we used to resolve the trait ref. We explicitly stored those back onto + // the item segment, since there's no other good place to put them. + // + // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. + // And this is exercised in: + // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index a8c8a85c5aa68..af64901ace022 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -16,4 +16,22 @@ fn bar (): Send>>() {} fn baz>() {} //~^ ERROR return type notation arguments must be elided with `..` +fn foo_path() where T::method(i32): Send {} +//~^ ERROR argument types not allowed with return type notation + +fn bar_path() where T::method() -> (): Send {} +//~^ ERROR return type not allowed with return type notation + +fn baz_path() where T::method(): Send {} +//~^ ERROR return type notation arguments must be elided with `..` + +fn foo_qualified() where ::method(i32): Send {} +//~^ ERROR expected associated type + +fn bar_qualified() where ::method() -> (): Send {} +//~^ ERROR expected associated type + +fn baz_qualified() where ::method(): Send {} +//~^ ERROR expected associated type + fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index 7e1695984f1c3..6808147008756 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -1,3 +1,21 @@ +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:28:36 + | +LL | fn foo_qualified() where ::method(i32): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:31:36 + | +LL | fn bar_qualified() where ::method() -> (): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a associated type + +error[E0575]: expected associated type, found associated function `Trait::method` + --> $DIR/bad-inputs-and-output.rs:34:36 + | +LL | fn baz_qualified() where ::method(): Send {} + | ^^^^^^^^^^^^^^^^^^^^^^ not a associated type + warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | @@ -25,5 +43,24 @@ error: return type notation arguments must be elided with `..` LL | fn baz>() {} | ^^ help: add `..`: `(..)` -error: aborting due to 3 previous errors; 1 warning emitted +error: argument types not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:19:40 + | +LL | fn foo_path() where T::method(i32): Send {} + | ^^^^^ help: remove the input types: `()` + +error: return type not allowed with return type notation + --> $DIR/bad-inputs-and-output.rs:22:42 + | +LL | fn bar_path() where T::method() -> (): Send {} + | ^^^^^^ help: remove the return type + +error: return type notation arguments must be elided with `..` + --> $DIR/bad-inputs-and-output.rs:25:40 + | +LL | fn baz_path() where T::method(): Send {} + | ^^ help: add `..`: `(..)` + +error: aborting due to 9 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0575`. diff --git a/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs new file mode 100644 index 0000000000000..d4f21f47c6c64 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs @@ -0,0 +1,52 @@ +//@ check-pass + +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Trait<'a> { + fn late<'b>(&'b self, _: &'a ()) -> impl Sized; + fn early<'b: 'b>(&'b self, _: &'a ()) -> impl Sized; +} + +#[allow(refining_impl_trait_internal)] +impl<'a> Trait<'a> for () { + fn late<'b>(&'b self, _: &'a ()) -> i32 { 1 } + fn early<'b: 'b>(&'b self, _: &'a ()) -> i32 { 1 } +} + +trait Other<'c> {} +impl Other<'_> for i32 {} + +fn test(t: &T) +where + T: for<'a, 'c> Trait<'a, late(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, + T: for<'a, 'c> Trait<'a, early(..): Other<'c>>, + // which is basically: + // for<'a, 'c> Trait<'a, for<'b> method<'b>: Other<'c>>, +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn test_path(t: &T) +where +T: for<'a> Trait<'a>, + for<'a, 'c> >::late(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> + for<'a, 'c> >::early(..): Other<'c>, + // which is basically: + // for<'a, 'b, 'c> >::method::<'b>: Other<'c> +{ + is_other_impl(t.late(&())); + is_other_impl(t.early(&())); +} + +fn is_other_impl(_: impl for<'c> Other<'c>) {} + +fn main() { + test(&()); + test(&()); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr new file mode 100644 index 0000000000000..c67231c07f723 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/higher-ranked-bound-works.rs:3:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs new file mode 100644 index 0000000000000..9bdc2d00233e0 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.rs @@ -0,0 +1,42 @@ +//@ check-pass + +#![allow(non_camel_case_types)] +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +trait Foo { + type test; + + fn test() -> impl Bar; +} + +fn call_path() +where + T::test(..): Bar, +{ +} + +fn call_bound>() {} + +trait Bar {} +struct NotBar; +struct YesBar; +impl Bar for YesBar {} + +impl Foo for () { + type test = NotBar; + + // Use refinement here so we can observe `YesBar: Bar`. + #[allow(refining_impl_trait_internal)] + fn test() -> YesBar { + YesBar + } +} + +fn main() { + // If `T::test(..)` resolved to the GAT (erroneously), then this would be + // an error since `<() as Foo>::bar` -- the associated type -- does not + // implement `Bar`, but the return type of the method does. + call_path::<()>(); + call_bound::<()>(); +} diff --git a/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr new file mode 100644 index 0000000000000..f4ece074b2856 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/namespace-conflict.stderr @@ -0,0 +1,11 @@ +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/namespace-conflict.rs:4:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs index d283c6eab370d..35d6dd799c703 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.rs @@ -5,7 +5,10 @@ trait Trait { fn method() {} } -fn test>() {} -//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` +fn bound>() {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` + +fn path() where T: Trait, T::method(..): Send {} +//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait` fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr index 79ced3c96ed5c..e308c927bf0e8 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/non-rpitit.stderr @@ -8,15 +8,26 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error: return type notation used on function that is not `async` and does not return `impl Trait` - --> $DIR/non-rpitit.rs:8:18 + --> $DIR/non-rpitit.rs:8:19 | LL | fn method() {} | ----------- this function must be `async` or return `impl Trait` ... -LL | fn test>() {} - | ^^^^^^^^^^^^^^^^ +LL | fn bound>() {} + | ^^^^^^^^^^^^^^^^ | = note: function returns `()`, which is not compatible with associated type return bounds -error: aborting due to 1 previous error; 1 warning emitted +error: return type notation used on function that is not `async` and does not return `impl Trait` + --> $DIR/non-rpitit.rs:11:30 + | +LL | fn method() {} + | ----------- this function must be `async` or return `impl Trait` +... +LL | fn path() where T: Trait, T::method(..): Send {} + | ^^^^^^^^^^^^^ + | + = note: function returns `()`, which is not compatible with associated type return bounds + +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs new file mode 100644 index 0000000000000..d94ec6b74d9d2 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.rs @@ -0,0 +1,42 @@ +#![feature(return_type_notation)] +//~^ WARN the feature `return_type_notation` is incomplete + +fn function() {} + +fn not_a_method() +where + function(..): Send, + //~^ ERROR expected function, found function `function` + //~| ERROR return type notation not allowed in this position yet +{ +} + +fn not_a_method_and_typoed() +where + function(): Send, + //~^ ERROR expected type, found function `function` +{ +} + +trait Tr { + fn method(); +} + +// Forgot the `T::` +fn maybe_method_overlaps() +where + method(..): Send, + //~^ ERROR cannot find function `method` in this scope + //~| ERROR return type notation not allowed in this position yet +{ +} + +// Forgot the `T::`, AND typoed `(..)` to `()` +fn maybe_method_overlaps_and_typoed() +where + method(): Send, + //~^ ERROR cannot find type `method` in this scope +{ +} + +fn main() {} diff --git a/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr new file mode 100644 index 0000000000000..8add2d4629675 --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/not-a-method.stderr @@ -0,0 +1,49 @@ +error[E0575]: expected function, found function `function` + --> $DIR/not-a-method.rs:8:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ not a function + +error[E0573]: expected type, found function `function` + --> $DIR/not-a-method.rs:16:5 + | +LL | function(): Send, + | ^^^^^^^^^^ not a type + +error[E0576]: cannot find function `method` in this scope + --> $DIR/not-a-method.rs:28:5 + | +LL | method(..): Send, + | ^^^^^^ not found in this scope + +error[E0412]: cannot find type `method` in this scope + --> $DIR/not-a-method.rs:37:5 + | +LL | method(): Send, + | ^^^^^^ not found in this scope + +warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/not-a-method.rs:1:12 + | +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #109417 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:8:5 + | +LL | function(..): Send, + | ^^^^^^^^^^^^ + +error: return type notation not allowed in this position yet + --> $DIR/not-a-method.rs:28:5 + | +LL | method(..): Send, + | ^^^^^^^^^^ + +error: aborting due to 6 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0412, E0573, E0575, E0576. +For more information about an error, try `rustc --explain E0412`. From a35da65409c8a4c834b5df35d8955e287ae569e1 Mon Sep 17 00:00:00 2001 From: Veera Date: Sat, 21 Sep 2024 11:11:11 -0400 Subject: [PATCH 19/23] Update Tests --- .../evade-deduplication-issue-118612.rs | 24 +++++++++++++++++++ .../evade-deduplication-issue-118612.stderr | 20 ++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs create mode 100644 tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs new file mode 100644 index 0000000000000..a2d34eaa384c9 --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.rs @@ -0,0 +1,24 @@ +//@ check-pass + +#![allow(long_running_const_eval)] + +//@ compile-flags: -Z tiny-const-eval-limit -Z deduplicate-diagnostics=yes +const FOO: () = { + let mut i = 0; + loop { + //~^ WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + //~| WARN is taking a long time + if i == 1000 { + break; + } else { + i += 1; + } + } +}; + +fn main() { + FOO +} diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr new file mode 100644 index 0000000000000..b894b7b2132df --- /dev/null +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr @@ -0,0 +1,20 @@ +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: 1 warning emitted + From 669f610f741f41bc8b2bef41d088589db4180355 Mon Sep 17 00:00:00 2001 From: Veera Date: Sat, 21 Sep 2024 11:23:34 -0400 Subject: [PATCH 20/23] Prevent Deduplication of `LongRunningWarn` --- .../src/const_eval/machine.rs | 9 ++- compiler/rustc_const_eval/src/errors.rs | 2 + .../evade-deduplication-issue-118612.stderr | 74 ++++++++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 7405ca09342da..2025a465a2289 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -641,7 +641,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // current number of evaluated terminators is a power of 2. The latter gives us a cheap // way to implement exponential backoff. let span = ecx.cur_span(); - ecx.tcx.dcx().emit_warn(LongRunningWarn { span, item_span: ecx.tcx.span }); + // We store a unique number in `force_duplicate` to evade `-Z deduplicate-diagnostics`. + // `new_steps` is guaranteed to be unique because `ecx.machine.num_evaluated_steps` is + // always increasing. + ecx.tcx.dcx().emit_warn(LongRunningWarn { + span, + item_span: ecx.tcx.span, + force_duplicate: new_steps, + }); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 0b366b43f95f6..bdd8c66bc244d 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -243,6 +243,8 @@ pub struct LongRunningWarn { pub span: Span, #[help] pub item_span: Span, + // Used for evading `-Z deduplicate-diagnostics`. + pub force_duplicate: usize, } #[derive(Subdiagnostic)] diff --git a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr index b894b7b2132df..cb19c59b15bc0 100644 --- a/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr +++ b/tests/ui/consts/const-eval/stable-metric/evade-deduplication-issue-118612.stderr @@ -16,5 +16,77 @@ help: the constant being evaluated LL | const FOO: () = { | ^^^^^^^^^^^^^ -warning: 1 warning emitted +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: constant evaluation is taking a long time + --> $DIR/evade-deduplication-issue-118612.rs:8:5 + | +LL | / loop { +LL | | +LL | | +LL | | +... | +LL | | } +LL | | } + | |_____^ the const evaluator is currently interpreting this expression + | +help: the constant being evaluated + --> $DIR/evade-deduplication-issue-118612.rs:6:1 + | +LL | const FOO: () = { + | ^^^^^^^^^^^^^ + +warning: 5 warnings emitted From 93993c77f55047cc1774fdfee4bcca9d43592c2a Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sat, 21 Sep 2024 08:48:28 -0700 Subject: [PATCH 21/23] compiler: Accept "improper" ctypes in extern "rust-cold" fn --- compiler/rustc_lint/src/types.rs | 5 ++++- .../ui/lint/rust-cold-fn-accept-improper-ctypes.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index f9d0cd49708ae..3d042f217452f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1320,7 +1320,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn is_internal_abi(&self, abi: SpecAbi) -> bool { - matches!(abi, SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic) + matches!( + abi, + SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustCold | SpecAbi::RustIntrinsic + ) } /// Find any fn-ptr types with external ABIs in `ty`. diff --git a/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs b/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs new file mode 100644 index 0000000000000..dc929e14527f4 --- /dev/null +++ b/tests/ui/lint/rust-cold-fn-accept-improper-ctypes.rs @@ -0,0 +1,14 @@ +//@ check-pass +#![feature(rust_cold_cc)] + +// extern "rust-cold" is a "Rust" ABI so we accept `repr(Rust)` types as arg/ret without warnings. + +pub extern "rust-cold" fn f(_: ()) -> Result<(), ()> { + Ok(()) +} + +extern "rust-cold" { + pub fn g(_: ()) -> Result<(), ()>; +} + +fn main() {} From a846d55d46c80660b6a311c6393fb66e486a7d43 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 21 Sep 2024 11:37:20 -0400 Subject: [PATCH 22/23] Assert that explicit_super_predicates_of and explicit_item_bounds truly only bounds for the type itself --- .../src/collect/item_bounds.rs | 32 +++++++---- .../src/collect/predicates_of.rs | 54 +++++++++++++++++++ 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d62727e76b586..7a254c884c294 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -10,6 +10,7 @@ use rustc_span::Span; use rustc_type_ir::Upcast; use tracing::{debug, instrument}; +use super::predicates_of::assert_only_contains_predicates_from; use super::ItemCtxt; use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter}; @@ -56,6 +57,9 @@ fn associated_type_bounds<'tcx>( tcx.def_path_str(assoc_item_def_id.to_def_id()), all_bounds ); + + assert_only_contains_predicates_from(filter, all_bounds, item_ty); + all_bounds } @@ -108,18 +112,21 @@ pub(super) fn explicit_item_bounds_with_filter( Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { let item = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_item(); let opaque_ty = item.expect_opaque_ty(); - return ty::EarlyBinder::bind(opaque_type_bounds( + let item_ty = Ty::new_projection_from_args( + tcx, + def_id.to_def_id(), + ty::GenericArgs::identity_for_item(tcx, def_id), + ); + let bounds = opaque_type_bounds( tcx, opaque_def_id.expect_local(), opaque_ty.bounds, - Ty::new_projection_from_args( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ), + item_ty, item.span, filter, - )); + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + return ty::EarlyBinder::bind(bounds); } Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!( tcx.def_span(def_id), @@ -167,7 +174,9 @@ pub(super) fn explicit_item_bounds_with_filter( }) => { let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) + let bounds = opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } // Since RPITITs are lowered as projections in `::lower_ty`, when we're // asking for the item bounds of the *opaques* in a trait's default method signature, we @@ -184,15 +193,18 @@ pub(super) fn explicit_item_bounds_with_filter( }; let args = GenericArgs::identity_for_item(tcx, def_id); let item_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args); - tcx.arena.alloc_slice( + let bounds = &*tcx.arena.alloc_slice( &opaque_type_bounds(tcx, def_id, bounds, item_ty, *span, filter) .to_vec() .fold_with(&mut AssocTyToOpaque { tcx, fn_def_id: fn_def_id.to_def_id() }), - ) + ); + assert_only_contains_predicates_from(filter, bounds, item_ty); + bounds } hir::Node::Item(hir::Item { kind: hir::ItemKind::TyAlias(..), .. }) => &[], _ => bug!("item_bounds called on {:?}", def_id), }; + ty::EarlyBinder::bind(bounds) } diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 7243e85ce98d2..cb98aa3d31591 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -676,9 +676,63 @@ pub(super) fn implied_predicates_with_filter<'tcx>( _ => {} } + assert_only_contains_predicates_from(filter, implied_bounds, tcx.types.self_param); + ty::EarlyBinder::bind(implied_bounds) } +// Make sure when elaborating supertraits, probing for associated types, etc., +// we really truly are elaborating clauses that have `Self` as their self type. +// This is very important since downstream code relies on this being correct. +pub(super) fn assert_only_contains_predicates_from<'tcx>( + filter: PredicateFilter, + bounds: &'tcx [(ty::Clause<'tcx>, Span)], + ty: Ty<'tcx>, +) { + if !cfg!(debug_assertions) { + return; + } + + match filter { + PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => { + for (clause, _) in bounds { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_predicate) => { + assert_eq!( + trait_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::Projection(projection_predicate) => { + assert_eq!( + projection_predicate.self_ty(), + ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + ty::ClauseKind::TypeOutlives(outlives_predicate) => { + assert_eq!( + outlives_predicate.0, ty, + "expected `Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + + ty::ClauseKind::RegionOutlives(_) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) => { + bug!( + "unexpected non-`Self` predicate when computing `{filter:?}` implied bounds: {clause:?}" + ); + } + } + } + } + PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {} + } +} + /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. #[instrument(level = "trace", skip(tcx))] From 4f3d06f5aa23e0447e477e35915ba2706351a073 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 21 Sep 2024 11:36:44 -0400 Subject: [PATCH 23/23] Don't elaborate effects predicates into bounds list unless we're actually collecting implied bounds, not super bounds --- compiler/rustc_hir_analysis/src/bounds.rs | 8 +++++++- .../rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 1 + .../rfcs/rfc-2632-const-trait-impl/assoc-type.rs | 1 - .../rfc-2632-const-trait-impl/assoc-type.stderr | 14 +------------- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index d0b0c08aa798b..14ea781629133 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -9,6 +9,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::def_id::DefId; use rustc_span::Span; +use crate::hir_ty_lowering::OnlySelfBounds; + /// Collects together a list of type bounds. These lists of bounds occur in many places /// in Rust's syntax: /// @@ -50,6 +52,7 @@ impl<'tcx> Bounds<'tcx> { span: Span, polarity: ty::PredicatePolarity, constness: ty::BoundConstness, + only_self_bounds: OnlySelfBounds, ) { let clause = ( bound_trait_ref @@ -66,7 +69,10 @@ impl<'tcx> Bounds<'tcx> { self.clauses.push(clause); } - if !tcx.features().effects { + // FIXME(effects): Lift this out of `push_trait_bound`, and move it somewhere else. + // Perhaps moving this into `lower_poly_trait_ref`, just like we lower associated + // type bounds. + if !tcx.features().effects || only_self_bounds.0 { return; } // For `T: ~const Tr` or `T: const Tr`, we need to add an additional bound on the diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 7163352e8a439..3986197ef7c08 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -719,6 +719,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, polarity, constness, + only_self_bounds, ); let mut dup_constraints = FxIndexMap::default(); diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs index 348bf839b6995..ea3cbabf3020b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.rs @@ -39,7 +39,6 @@ impl const Foo for NonConstAdd { #[const_trait] trait Baz { type Qux: Add; - //~^ ERROR the trait bound } impl const Baz for NonConstAdd { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr index 405212b52c7c7..c20b53c210fe6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr @@ -12,17 +12,5 @@ error: using `#![feature(effects)]` without enabling next trait solver globally = note: the next trait solver must be enabled globally for the effects feature to work correctly = help: use `-Znext-solver` to enable -error[E0277]: the trait bound `Add::{synthetic#0}: Compat` is not satisfied - --> $DIR/assoc-type.rs:41:15 - | -LL | type Qux: Add; - | ^^^ the trait `Compat` is not implemented for `Add::{synthetic#0}` - | -help: consider further restricting the associated type - | -LL | trait Baz where Add::{synthetic#0}: Compat { - | ++++++++++++++++++++++++++++++++ - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 1 previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0277`.