Auto merge of #130674 - compiler-errors:rollup-yu105fl, r=compiler-errors
Rollup of 8 pull requests Successful merges: - #127766 (add `extern "C-cmse-nonsecure-entry" fn` ) - #129629 (Implement Return Type Notation (RTN)'s path form in where clauses) - #130408 (Avoid re-validating UTF-8 in `FromUtf8Error::into_utf8_lossy`) - #130651 (Add --enable-profiler to armhf dist) - #130653 (ABI compatibility: mention Result guarantee) - #130666 (Assert that `explicit_super_predicates_of` and `explicit_item_super_predicates` truly only contains bounds for the type itself) - #130667 (compiler: Accept "improper" ctypes in extern "rust-cold" fn) - #130673 (Parser: recover from `:::` to `::`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
764e6aec81
115 changed files with 2213 additions and 455 deletions
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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<Expr>]) -> &'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,
|
||||
);
|
||||
|
|
|
@ -485,9 +485,23 @@ enum ParamMode {
|
|||
Optional,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
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> {
|
||||
|
@ -1226,7 +1240,15 @@ 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,
|
||||
AllowReturnTypeNotation::Yes,
|
||||
itctx,
|
||||
None,
|
||||
);
|
||||
self.ty_path(id, t.span, qpath)
|
||||
}
|
||||
|
||||
|
@ -2203,6 +2225,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&None,
|
||||
&p.path,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
itctx,
|
||||
Some(modifiers),
|
||||
) {
|
||||
|
@ -2341,6 +2364,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
@ -2419,6 +2443,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
|
|
@ -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,10 +16,9 @@ use super::errors::{
|
|||
GenericTypeWithParentheses, UseAngleBrackets,
|
||||
};
|
||||
use super::{
|
||||
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))]
|
||||
|
@ -28,6 +28,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
qself: &Option<ptr::P<QSelf>>,
|
||||
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<ast::TraitBoundModifiers>,
|
||||
|
@ -103,8 +104,14 @@ 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,
|
||||
Res::Err => GenericArgsMode::Silence,
|
||||
// An error
|
||||
_ => GenericArgsMode::Err,
|
||||
};
|
||||
|
@ -164,11 +171,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
|
||||
// * final path is `<<<std::vec::Vec<T>>::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,11 +254,46 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
|
||||
}
|
||||
GenericArgs::Parenthesized(data) => match generic_args_mode {
|
||||
GenericArgsMode::ParenSugar => self.lower_parenthesized_parameter_data(
|
||||
data,
|
||||
itctx,
|
||||
bound_modifier_allowed_features,
|
||||
),
|
||||
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 | 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<params...>`
|
||||
let sub = if !data.inputs.is_empty() {
|
||||
|
@ -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 | GenericArgsMode::Silence => {
|
||||
// Ok
|
||||
}
|
||||
GenericArgsMode::ParenSugar | GenericArgsMode::Err => {
|
||||
self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span });
|
||||
}
|
||||
}
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<Conv> 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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M
|
||||
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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,11 +502,12 @@ 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,
|
||||
mpart_sugg,
|
||||
what: "type",
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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 `<dyn HirTyLowerer>::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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
@ -676,9 +677,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))]
|
||||
|
@ -770,6 +825,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 +839,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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
@ -1635,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> <T as Trait<'a>>::x::<'r, T>::{opaque#0}: for<'b> Other<'b>`.
|
||||
// `for<'a> for<'r> <T as Trait<'a>>::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
|
||||
|
@ -1839,6 +1844,178 @@ 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));
|
||||
}
|
||||
|
||||
// When we have a return type notation type in a where clause, like
|
||||
// `where <T as Trait>::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>();
|
||||
// }
|
||||
// ```
|
||||
// and a bound that looks like:
|
||||
// `for<'a, 'b> <T as Trait<'a>>::x(): Other<'b>`
|
||||
// this is going to expand to something like:
|
||||
// `for<'a, 'b, 'r> <T as Trait<'a>>::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 {
|
||||
// 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 {
|
||||
// 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| {
|
||||
matches!(
|
||||
args.parenthesized,
|
||||
hir::GenericArgsParentheses::ReturnTypeNotation
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
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.
|
||||
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.
|
||||
// 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;
|
||||
};
|
||||
|
||||
// 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;
|
||||
};
|
||||
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)
|
||||
}
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// 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(
|
||||
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());
|
||||
|
||||
// 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.
|
||||
//
|
||||
// For example, in `where for<'a> <T as Trait<'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);
|
||||
self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved);
|
||||
}
|
||||
}
|
||||
|
||||
/// Detects late-bound lifetimes and inserts them into
|
||||
|
|
|
@ -780,14 +780,15 @@ 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}")]
|
||||
pub inferred_sugg: Option<Span>,
|
||||
pub bound: String,
|
||||
#[subdiagnostic]
|
||||
pub mpart_sugg: Option<AssociatedTypeTraitUninferredGenericParamsMultipartSuggestion>,
|
||||
pub mpart_sugg: Option<AssociatedItemTraitUninferredGenericParamsMultipartSuggestion>,
|
||||
pub what: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
@ -795,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,
|
||||
|
@ -1693,3 +1694,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,
|
||||
}
|
||||
|
|
|
@ -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,269 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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);
|
||||
};
|
||||
|
||||
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
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
// We don't allow generics on the module segments.
|
||||
let _ =
|
||||
self.prohibit_generic_args(mod_segments.iter(), GenericsArgsErrExtend::None);
|
||||
|
||||
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);
|
||||
|
||||
// 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,
|
||||
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,
|
||||
);
|
||||
|
||||
// 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> <T as Trait<'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));
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform type-dependent lookup for a *method* for return type notation.
|
||||
/// This generally mirrors `<dyn HirTyLowerer>::lower_assoc_path`.
|
||||
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,
|
||||
)?,
|
||||
_ => {
|
||||
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> <T as Tr<'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`, since we'd need to introduce those as elided
|
||||
// bound vars on the where clause too.
|
||||
if bound.has_bound_vars() {
|
||||
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();
|
||||
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))
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
item_def_id: DefId,
|
||||
path_span: Span,
|
||||
) -> Result<ty::AliasTy<'tcx>, 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.
|
||||
|
|
|
@ -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;
|
||||
|
@ -719,6 +719,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
span,
|
||||
polarity,
|
||||
constness,
|
||||
only_self_bounds,
|
||||
);
|
||||
|
||||
let mut dup_constraints = FxIndexMap::default();
|
||||
|
@ -813,17 +814,19 @@ 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.
|
||||
///
|
||||
/// `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<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
|
||||
|
@ -841,7 +844,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 +1084,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 +1549,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 `<Self as ..>` 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 +1563,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 `<Self as ..>` 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<Item = &'a hir::PathSegment<'a>> + Clone,
|
||||
|
@ -1930,7 +1940,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!(
|
||||
|
@ -2061,6 +2071,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));
|
||||
|
@ -2085,6 +2106,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
}) =>
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1191,6 +1191,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) ->
|
|||
| RiscvInterruptM
|
||||
| RiscvInterruptS
|
||||
| CCmseNonSecureCall
|
||||
| CCmseNonSecureEntry
|
||||
| Unadjusted => false,
|
||||
Rust | RustCall | RustCold | RustIntrinsic => {
|
||||
tcx.sess.panic_strategy() == PanicStrategy::Unwind
|
||||
|
|
|
@ -670,7 +670,7 @@ parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call
|
|||
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
|
||||
parse_parenthesized_lifetime_suggestion = remove the parentheses
|
||||
|
||||
parse_path_single_colon = path separator must be a double colon
|
||||
parse_path_double_colon = path separator must be a double colon
|
||||
.suggestion = use a double colon instead
|
||||
|
||||
parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
|
||||
|
|
|
@ -1571,7 +1571,7 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
|
|||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_path_single_colon)]
|
||||
#[diag(parse_path_double_colon)]
|
||||
pub(crate) struct PathSingleColon {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
@ -1583,6 +1583,14 @@ pub(crate) struct PathSingleColon {
|
|||
pub type_ascription: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_path_double_colon)]
|
||||
pub(crate) struct PathTripleColon {
|
||||
#[primary_span]
|
||||
#[suggestion(applicability = "maybe-incorrect", code = "", style = "verbose")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_colon_as_semi)]
|
||||
pub(crate) struct ColonAsSemi {
|
||||
|
|
|
@ -707,7 +707,7 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
};
|
||||
|
||||
let (ident, item_kind) = if self.eat(&token::PathSep) {
|
||||
let (ident, item_kind) = if self.eat_path_sep() {
|
||||
let suffixes = if self.eat(&token::BinOp(token::Star)) {
|
||||
None
|
||||
} else {
|
||||
|
@ -1054,7 +1054,7 @@ impl<'a> Parser<'a> {
|
|||
{
|
||||
// `use *;` or `use ::*;` or `use {...};` or `use ::{...};`
|
||||
let mod_sep_ctxt = self.token.span.ctxt();
|
||||
if self.eat(&token::PathSep) {
|
||||
if self.eat_path_sep() {
|
||||
prefix
|
||||
.segments
|
||||
.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
|
||||
|
@ -1065,7 +1065,7 @@ impl<'a> Parser<'a> {
|
|||
// `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;`
|
||||
prefix = self.parse_path(PathStyle::Mod)?;
|
||||
|
||||
if self.eat(&token::PathSep) {
|
||||
if self.eat_path_sep() {
|
||||
self.parse_use_tree_glob_or_nested()?
|
||||
} else {
|
||||
// Recover from using a colon as path separator.
|
||||
|
|
|
@ -1562,12 +1562,25 @@ impl<'a> Parser<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Checks for `::` or, potentially, `:::` and then look ahead after it.
|
||||
fn check_path_sep_and_look_ahead(&mut self, looker: impl Fn(&Token) -> bool) -> bool {
|
||||
if self.check(&token::PathSep) {
|
||||
if self.may_recover() && self.look_ahead(1, |t| t.kind == token::Colon) {
|
||||
debug_assert!(!self.look_ahead(1, &looker), "Looker must not match on colon");
|
||||
self.look_ahead(2, looker)
|
||||
} else {
|
||||
self.look_ahead(1, looker)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// `::{` or `::*`
|
||||
fn is_import_coupler(&mut self) -> bool {
|
||||
self.check(&token::PathSep)
|
||||
&& self.look_ahead(1, |t| {
|
||||
*t == token::OpenDelim(Delimiter::Brace) || *t == token::BinOp(token::Star)
|
||||
})
|
||||
self.check_path_sep_and_look_ahead(|t| {
|
||||
matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::BinOp(token::Star))
|
||||
})
|
||||
}
|
||||
|
||||
// Debug view of the parser's token stream, up to `{lookahead}` tokens.
|
||||
|
|
|
@ -16,7 +16,7 @@ use tracing::debug;
|
|||
|
||||
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
|
||||
use super::{Parser, Restrictions, TokenType};
|
||||
use crate::errors::PathSingleColon;
|
||||
use crate::errors::{PathSingleColon, PathTripleColon};
|
||||
use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma};
|
||||
use crate::{errors, maybe_whole};
|
||||
|
||||
|
@ -210,7 +210,7 @@ impl<'a> Parser<'a> {
|
|||
let lo = self.token.span;
|
||||
let mut segments = ThinVec::new();
|
||||
let mod_sep_ctxt = self.token.span.ctxt();
|
||||
if self.eat(&token::PathSep) {
|
||||
if self.eat_path_sep() {
|
||||
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
|
||||
}
|
||||
self.parse_path_segments(&mut segments, style, ty_generics)?;
|
||||
|
@ -246,7 +246,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
segments.push(segment);
|
||||
|
||||
if self.is_import_coupler() || !self.eat(&token::PathSep) {
|
||||
if self.is_import_coupler() || !self.eat_path_sep() {
|
||||
if style == PathStyle::Expr
|
||||
&& self.may_recover()
|
||||
&& self.token == token::Colon
|
||||
|
@ -272,6 +272,18 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Eat `::` or, potentially, `:::`.
|
||||
#[must_use]
|
||||
pub(super) fn eat_path_sep(&mut self) -> bool {
|
||||
let result = self.eat(&token::PathSep);
|
||||
if result && self.may_recover() {
|
||||
if self.eat_noexpect(&token::Colon) {
|
||||
self.dcx().emit_err(PathTripleColon { span: self.prev_token.span });
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub(super) fn parse_path_segment(
|
||||
&mut self,
|
||||
style: PathStyle,
|
||||
|
@ -297,9 +309,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
Ok(
|
||||
if style == PathStyle::Type && check_args_start(self)
|
||||
|| style != PathStyle::Mod
|
||||
&& self.check(&token::PathSep)
|
||||
&& self.look_ahead(1, |t| is_args_start(t))
|
||||
|| style != PathStyle::Mod && self.check_path_sep_and_look_ahead(is_args_start)
|
||||
{
|
||||
// We use `style == PathStyle::Expr` to check if this is in a recursion or not. If
|
||||
// it isn't, then we reset the unmatched angle bracket count as we're about to start
|
||||
|
@ -310,7 +320,8 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
|
||||
// First, eat `::` if it exists.
|
||||
let _ = self.eat(&token::PathSep);
|
||||
let _ = self.eat_path_sep();
|
||||
|
||||
let lo = self.token.span;
|
||||
let args = if self.eat_lt() {
|
||||
// `<'a, T, A = U>`
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,20 @@ 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);
|
||||
|
||||
// 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(..))
|
||||
{
|
||||
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 +1941,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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2724,7 +2724,10 @@ impl Target {
|
|||
}
|
||||
X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
|
||||
Aapcs { .. } => "arm" == self.arch,
|
||||
CCmseNonSecureCall => ["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",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -433,6 +433,7 @@ pub enum CallConvention {
|
|||
// Target-specific calling conventions.
|
||||
ArmAapcs,
|
||||
CCmseNonSecureCall,
|
||||
CCmseNonSecureEntry,
|
||||
|
||||
Msp430Intr,
|
||||
|
||||
|
|
|
@ -1062,6 +1062,7 @@ pub enum Abi {
|
|||
AvrInterrupt,
|
||||
AvrNonBlockingInterrupt,
|
||||
CCmseNonSecureCall,
|
||||
CCmseNonSecureEntry,
|
||||
System { unwind: bool },
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
|
|
|
@ -2087,7 +2087,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`.
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -1761,6 +1761,8 @@ mod prim_ref {}
|
|||
/// - `i32` is ABI-compatible with `NonZero<i32>`, 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<T>` are ABI-compatible.
|
||||
/// Furthermore, if `U` satisfies the requirements [outlined here](result/index.html#representation),
|
||||
/// then `T` and `Result<T, U>` and `Result<U, T>` are all ABI-compatible.
|
||||
///
|
||||
/// Furthermore, ABI compatibility satisfies the following general properties:
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|||
<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
|
||||
|
||||
``` 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
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
26
tests/assembly/cmse.rs
Normal file
26
tests/assembly/cmse.rs
Normal file
|
@ -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) }
|
||||
}
|
|
@ -16,4 +16,22 @@ fn bar<T: Trait<method() -> (): Send>>() {}
|
|||
fn baz<T: Trait<method(): Send>>() {}
|
||||
//~^ ERROR return type notation arguments must be elided with `..`
|
||||
|
||||
fn foo_path<T: Trait>() where T::method(i32): Send {}
|
||||
//~^ ERROR argument types not allowed with return type notation
|
||||
|
||||
fn bar_path<T: Trait>() where T::method() -> (): Send {}
|
||||
//~^ ERROR return type not allowed with return type notation
|
||||
|
||||
fn baz_path<T: Trait>() where T::method(): Send {}
|
||||
//~^ ERROR return type notation arguments must be elided with `..`
|
||||
|
||||
fn foo_qualified<T: Trait>() where <T as Trait>::method(i32): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn bar_qualified<T: Trait>() where <T as Trait>::method() -> (): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn baz_qualified<T: Trait>() where <T as Trait>::method(): Send {}
|
||||
//~^ ERROR expected associated type
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -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<T: Trait>() where <T as Trait>::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<T: Trait>() where <T as Trait>::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<T: Trait>() where <T as Trait>::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<T: Trait<method(): Send>>() {}
|
||||
| ^^ 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<T: Trait>() 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<T: Trait>() 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<T: Trait>() 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`.
|
||||
|
|
|
@ -10,17 +10,12 @@ trait Tr {
|
|||
fn foo<T: Tr>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR return type notation not allowed in this position yet
|
||||
//~| ERROR expected type, found function
|
||||
<T as Tr>::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
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
error[E0575]: expected associated type, found associated function `Tr::method`
|
||||
--> $DIR/bare-path.rs:15:5
|
||||
|
|
||||
LL | <T as Tr>::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,53 +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:19:23
|
||||
--> $DIR/bare-path.rs:15:23
|
||||
|
|
||||
LL | let _ = T::CONST::(..);
|
||||
| ^^^^
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:21:21
|
||||
--> $DIR/bare-path.rs:17:12
|
||||
|
|
||||
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: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/bare-path.rs:15:22
|
||||
|
|
||||
LL | <T as Tr>::method(..): Send,
|
||||
| ^^^^
|
||||
|
||||
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: expected type, found function
|
||||
--> $DIR/bare-path.rs:21:15
|
||||
|
|
||||
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 7 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0575`.
|
||||
|
|
|
@ -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: &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: &T)
|
||||
where
|
||||
T: for<'a> Trait<'a>,
|
||||
for<'a, 'c> <T as Trait<'a>>::late(..): Other<'c>,
|
||||
// which is basically:
|
||||
// for<'a, 'b, 'c> <T as Trait<'a>>::method::<'b>: Other<'c>
|
||||
for<'a, 'c> <T as Trait<'a>>::early(..): Other<'c>,
|
||||
// which is basically:
|
||||
// for<'a, 'b, 'c> <T as Trait<'a>>::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(&());
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -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<T: Foo>()
|
||||
where
|
||||
T::test(..): Bar,
|
||||
{
|
||||
}
|
||||
|
||||
fn call_bound<T: Foo<test(..): Bar>>() {}
|
||||
|
||||
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::<()>();
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -5,7 +5,10 @@ trait Trait {
|
|||
fn method() {}
|
||||
}
|
||||
|
||||
fn test<T: Trait<method(..): Send>>() {}
|
||||
//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
fn bound<T: Trait<method(..): Send>>() {}
|
||||
//~^ ERROR return type notation used on function that is not `async` and does not return `impl Trait`
|
||||
|
||||
fn path<T>() 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() {}
|
||||
|
|
|
@ -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<T: Trait<method(..): Send>>() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
LL | fn bound<T: Trait<method(..): Send>>() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= 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<T>() 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
|
||||
|
||||
|
|
|
@ -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<T: Tr>()
|
||||
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<T: Tr>()
|
||||
where
|
||||
method(): Send,
|
||||
//~^ ERROR cannot find type `method` in this scope
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -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<T: A + B>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function `method` in bounds of `T`
|
||||
{
|
||||
}
|
||||
|
||||
trait Sub: A + B {}
|
||||
|
||||
fn ambiguous_via_supertrait<T: Sub>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ ERROR ambiguous associated function `method` in bounds of `T`
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 | <T as B>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as A>::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 | <T as B>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
help: use fully-qualified syntax to disambiguate
|
||||
|
|
||||
LL | <T as A>::method(..): Send,
|
||||
| ~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0221`.
|
|
@ -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>(T);
|
||||
|
||||
impl<T> W<T> {
|
||||
fn test()
|
||||
where
|
||||
T: Trait,
|
||||
T::method(..): Send,
|
||||
{
|
||||
is_send(T::method());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -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<T>()
|
||||
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<T>()
|
||||
where
|
||||
T: B,
|
||||
T::method(..): Send,
|
||||
//~^ ERROR cannot use the associated function of a trait with uninferred generic parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 | <T as A<'_>>::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 | <T as A<'_>>::method(..): Send,
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0212`.
|
|
@ -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<T: A>()
|
||||
where
|
||||
<T as A>::method(..): Send,
|
||||
//~^ ERROR cannot find method or associated constant `method` in trait `A`
|
||||
<T as A>::bad(..): Send,
|
||||
//~^ ERROR expected method or associated constant, found associated type `A::bad`
|
||||
{
|
||||
}
|
||||
|
||||
fn type_dependent<T: A>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
//~^ associated function `method` not found for `T`
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,33 @@
|
|||
error[E0576]: cannot find method or associated constant `method` in trait `A`
|
||||
--> $DIR/path-missing.rs:11:15
|
||||
|
|
||||
LL | <T as A>::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 | <T as A>::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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -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() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 | <Example as Trait>::method: Send,
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0223`.
|
|
@ -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() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -0,0 +1,27 @@
|
|||
//@ 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 is_send(_: impl Send) {}
|
||||
|
||||
impl<T: Foo> Bar for T {
|
||||
fn other()
|
||||
where
|
||||
Self::method(..): Send,
|
||||
{
|
||||
is_send(Self::method());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(return_type_notation)]
|
||||
//~^ WARN the feature `return_type_notation` is incomplete
|
||||
|
||||
trait Foo {
|
||||
fn method<T>() -> impl Sized;
|
||||
}
|
||||
|
||||
fn test<T: Foo>()
|
||||
where
|
||||
<T as Foo>::method(..): Send,
|
||||
//~^ ERROR return type notation is not allowed for functions that have type parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn test_type_dependent<T: Foo>()
|
||||
where
|
||||
<T as Foo>::method(..): Send,
|
||||
//~^ ERROR return type notation is not allowed for functions that have type parameters
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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<T>() -> impl Sized;
|
||||
| - type parameter declared here
|
||||
...
|
||||
LL | <T as Foo>::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<T>() -> impl Sized;
|
||||
| - type parameter declared here
|
||||
...
|
||||
LL | <T as Foo>::method(..): Send,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
|
@ -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<T: Trait>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test::<DoesntWork>();
|
||||
//~^ ERROR `*mut ()` cannot be sent between threads safely
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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::<DoesntWork>();
|
||||
| ^^^^^^^^^^ `*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<T: Trait>()
|
||||
| ---- 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`.
|
|
@ -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<T: Trait>()
|
||||
where
|
||||
T::method(..): Send,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test::<Works>();
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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: aborting due to 1 previous error
|
||||
|
||||
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
|
||||
|
||||
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`.
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`.
|
|
@ -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]
|
||||
#[cmse_nonsecure_entry] //~ ERROR [E0775]
|
||||
pub extern "C" fn entry_function(input: u32) -> u32 {
|
||||
input + 6
|
||||
pub extern "C-cmse-nonsecure-entry" fn entry_function(input: u32) -> u32 {
|
||||
//~^ ERROR [E0570]
|
||||
input
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension
|
||||
--> $DIR/trustzone-only.rs:5:1
|
||||
|
|
||||
LL | #[cmse_nonsecure_entry]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0775`.
|
|
@ -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`.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue