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:
bors 2024-09-21 22:09:47 +00:00
commit 764e6aec81
115 changed files with 2213 additions and 455 deletions

View file

@ -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,
);

View file

@ -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,
);

View file

@ -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,
);

View file

@ -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,
);

View file

@ -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,
);

View file

@ -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(),

View file

@ -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");

View file

@ -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,

View file

@ -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);
}

View file

@ -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());

View file

@ -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

View file

@ -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]

View file

@ -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.

View file

@ -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,

View file

@ -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)),

View file

@ -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

View file

@ -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

View file

@ -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",
}),
)
}

View file

@ -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)
}

View file

@ -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;
};

View file

@ -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

View file

@ -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,
}

View file

@ -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.

View file

@ -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);

View file

@ -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`.

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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.

View file

@ -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.

View file

@ -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>`

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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),

View file

@ -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",

View file

@ -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

View file

@ -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",

View file

@ -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,

View file

@ -433,6 +433,7 @@ pub enum CallConvention {
// Target-specific calling conventions.
ArmAapcs,
CCmseNonSecureCall,
CCmseNonSecureEntry,
Msp430Intr,

View file

@ -1062,6 +1062,7 @@ pub enum Abi {
AvrInterrupt,
AvrNonBlockingInterrupt,
CCmseNonSecureCall,
CCmseNonSecureEntry,
System { unwind: bool },
RustIntrinsic,
RustCall,

View file

@ -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`.

View file

@ -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)]

View file

@ -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 = [

View file

@ -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:
///

View file

@ -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

View file

@ -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
}
```

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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
View 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) }
}

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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(&());
}

View file

@ -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

View file

@ -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::<()>();
}

View file

@ -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

View file

@ -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() {}

View file

@ -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

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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

View file

@ -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() {}

View file

@ -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

View file

@ -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
}

View file

@ -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`.

View file

@ -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>();
}

View file

@ -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

View file

@ -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

View file

@ -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`.

View file

@ -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)
}

View file

@ -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
}

View file

@ -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`.

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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