diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0077dec889d..77738b2c5cc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -46,7 +46,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
@@ -55,11 +55,9 @@ use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec};
use rustc_query_system::ich::StableHashingContext;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::lint::LintBuffer;
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
-use rustc_span::edition::Edition;
use rustc_span::hygiene::ExpnId;
use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1184,11 +1182,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::Ty<'hir> {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
- let ty = self.ty_path(id, t.span, qpath);
- if let hir::TyKind::TraitObject(..) = ty.kind {
- self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
- }
- ty
+ self.ty_path(id, t.span, qpath)
}
fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> {
@@ -1285,9 +1279,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
lifetime_bound.unwrap_or_else(|| this.elided_dyn_bound(t.span));
(bounds, lifetime_bound)
});
- if kind != TraitObjectSyntax::Dyn {
- self.maybe_lint_bare_trait(t.span, t.id, false);
- }
hir::TyKind::TraitObject(bounds, lifetime_bound, kind)
}
TyKind::ImplTrait(def_node_id, ref bounds) => {
@@ -2380,39 +2371,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
name: hir::LifetimeName::Implicit(missing),
}
}
-
- fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
- // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
- // call site which do not have a macro backtrace. See #61963.
- let is_macro_callsite = self
- .sess
- .source_map()
- .span_to_snippet(span)
- .map(|snippet| snippet.starts_with("#["))
- .unwrap_or(true);
- if !is_macro_callsite {
- if span.edition() < Edition::Edition2021 {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- BARE_TRAIT_OBJECTS,
- id,
- span,
- "trait objects without an explicit `dyn` are deprecated",
- BuiltinLintDiagnostics::BareTraitObject(span, is_global),
- )
- } else {
- let msg = "trait objects must include the `dyn` keyword";
- let label = "add `dyn` keyword before this trait";
- let mut err = struct_span_err!(self.sess, span, E0782, "{}", msg,);
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- label,
- String::from("dyn "),
- Applicability::MachineApplicable,
- );
- err.emit();
- }
- }
- }
}
/// Helper struct for delayed construction of GenericArgs.
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index d67d872b884..768cb99510f 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -8,13 +8,14 @@ use rustc_expand::base::{self, *};
use rustc_parse::parser::Parser;
use rustc_parse_format as parse;
use rustc_session::lint;
+use rustc_session::parse::ParseSess;
use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{InnerSpan, Span};
use rustc_target::asm::InlineAsmArch;
use smallvec::smallvec;
-struct AsmArgs {
+pub struct AsmArgs {
templates: Vec
>,
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap,
@@ -31,15 +32,28 @@ fn parse_args<'a>(
is_global_asm: bool,
) -> Result> {
let mut p = ecx.new_parser_from_tts(tts);
+ let sess = &ecx.sess.parse_sess;
+ parse_asm_args(&mut p, sess, sp, is_global_asm)
+}
+
+// Primarily public for rustfmt consumption.
+// Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
+pub fn parse_asm_args<'a>(
+ p: &mut Parser<'a>,
+ sess: &'a ParseSess,
+ sp: Span,
+ is_global_asm: bool,
+) -> Result> {
+ let diag = &sess.span_diagnostic;
if p.token == token::Eof {
- return Err(ecx.struct_span_err(sp, "requires at least a template string argument"));
+ return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
}
// Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
let mut err =
- ecx.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
+ diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
err.note("consider migrating to the new asm! syntax specified in RFC 2873");
err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
return Err(err);
@@ -61,7 +75,7 @@ fn parse_args<'a>(
if !p.eat(&token::Comma) {
if allow_templates {
// After a template string, we always expect *only* a comma...
- let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`");
+ let mut err = diag.struct_span_err(p.token.span, "expected token: `,`");
err.span_label(p.token.span, "expected `,`");
p.maybe_annotate_with_ascription(&mut err, false);
return Err(err);
@@ -76,14 +90,14 @@ fn parse_args<'a>(
// Parse clobber_abi
if p.eat_keyword(sym::clobber_abi) {
- parse_clobber_abi(&mut p, &mut args)?;
+ parse_clobber_abi(p, &mut args)?;
allow_templates = false;
continue;
}
// Parse options
if p.eat_keyword(sym::options) {
- parse_options(&mut p, &mut args, is_global_asm)?;
+ parse_options(p, &mut args, is_global_asm)?;
allow_templates = false;
continue;
}
@@ -103,25 +117,25 @@ fn parse_args<'a>(
let mut explicit_reg = false;
let op = if !is_global_asm && p.eat_keyword(kw::In) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
ast::InlineAsmOperand::In { reg, expr }
} else if !is_global_asm && p.eat_keyword(sym::out) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: false }
} else if !is_global_asm && p.eat_keyword(sym::lateout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
ast::InlineAsmOperand::Out { reg, expr, late: true }
} else if !is_global_asm && p.eat_keyword(sym::inout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
@@ -133,9 +147,9 @@ fn parse_args<'a>(
ast::InlineAsmOperand::InOut { reg, expr, late: false }
}
} else if !is_global_asm && p.eat_keyword(sym::inlateout) {
- let reg = parse_reg(&mut p, &mut explicit_reg)?;
+ let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = ecx.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
return Err(err);
}
let expr = p.parse_expr()?;
@@ -154,7 +168,7 @@ fn parse_args<'a>(
match expr.kind {
ast::ExprKind::Path(..) => {}
_ => {
- let err = ecx
+ let err = diag
.struct_span_err(expr.span, "argument to `sym` must be a path expression");
return Err(err);
}
@@ -173,7 +187,7 @@ fn parse_args<'a>(
} else {
"expected operand, clobber_abi, options, or additional template string"
};
- let mut err = ecx.struct_span_err(template.span, errstr);
+ let mut err = diag.struct_span_err(template.span, errstr);
err.span_label(template.span, errstr);
return Err(err);
}
@@ -193,31 +207,31 @@ fn parse_args<'a>(
// clobber_abi/options. We do this at the end once we have the full span
// of the argument available.
if !args.options_spans.is_empty() {
- ecx.struct_span_err(span, "arguments are not allowed after options")
+ diag.struct_span_err(span, "arguments are not allowed after options")
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
} else if let Some((_, abi_span)) = args.clobber_abis.last() {
- ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
+ diag.struct_span_err(span, "arguments are not allowed after clobber_abi")
.span_label(*abi_span, "clobber_abi")
.span_label(span, "argument")
.emit();
}
if explicit_reg {
if name.is_some() {
- ecx.struct_span_err(span, "explicit register arguments cannot have names").emit();
+ diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
}
args.reg_args.insert(slot);
} else if let Some(name) = name {
if let Some(&prev) = args.named_args.get(&name) {
- ecx.struct_span_err(span, &format!("duplicate argument named `{}`", name))
+ diag.struct_span_err(span, &format!("duplicate argument named `{}`", name))
.span_label(args.operands[prev].1, "previously here")
.span_label(span, "duplicate argument")
.emit();
continue;
}
if !args.reg_args.is_empty() {
- let mut err = ecx.struct_span_err(
+ let mut err = diag.struct_span_err(
span,
"named arguments cannot follow explicit register arguments",
);
@@ -230,7 +244,7 @@ fn parse_args<'a>(
args.named_args.insert(name, slot);
} else {
if !args.named_args.is_empty() || !args.reg_args.is_empty() {
- let mut err = ecx.struct_span_err(
+ let mut err = diag.struct_span_err(
span,
"positional arguments cannot follow named arguments \
or explicit register arguments",
@@ -251,21 +265,21 @@ fn parse_args<'a>(
&& args.options.contains(ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
+ diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
+ diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
.emit();
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- ecx.struct_span_err(
+ diag.struct_span_err(
spans,
"the `pure` option must be combined with either `nomem` or `readonly`",
)
@@ -296,14 +310,14 @@ fn parse_args<'a>(
}
}
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
- ecx.struct_span_err(
+ diag.struct_span_err(
args.options_spans.clone(),
"asm with the `pure` option must have at least one output",
)
.emit();
}
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
- let err = ecx
+ let err = diag
.struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option");
// Bail out now since this is likely to confuse MIR
@@ -312,7 +326,7 @@ fn parse_args<'a>(
if args.clobber_abis.len() > 0 {
if is_global_asm {
- let err = ecx.struct_span_err(
+ let err = diag.struct_span_err(
args.clobber_abis.iter().map(|(_, span)| *span).collect::>(),
"`clobber_abi` cannot be used with `global_asm!`",
);
@@ -321,7 +335,7 @@ fn parse_args<'a>(
return Err(err);
}
if !regclass_outputs.is_empty() {
- ecx.struct_span_err(
+ diag.struct_span_err(
regclass_outputs.clone(),
"asm with `clobber_abi` must specify explicit registers for outputs",
)
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index d768f06c4f0..d9faa6777ea 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -616,19 +616,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
match self.size_and_align_of(metadata, &field)? {
Some(size_and_align) => size_and_align,
None => {
- // A field with extern type. If this field is at offset 0, we behave
- // like the underlying extern type.
- // FIXME: Once we have made decisions for how to handle size and alignment
- // of `extern type`, this should be adapted. It is just a temporary hack
- // to get some code to work that probably ought to work.
- if sized_size == Size::ZERO {
- return Ok(None);
- } else {
- span_bug!(
- self.cur_span(),
- "Fields cannot be extern types, unless they are at offset 0"
- )
- }
+ // A field with an extern type. We don't know the actual dynamic size
+ // or the alignment.
+ return Ok(None);
}
};
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 851c2a6bb2e..818b95b7fc4 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -362,21 +362,15 @@ where
// Re-use parent metadata to determine dynamic field layout.
// With custom DSTS, this *will* execute user-defined code, but the same
// happens at run-time so that's okay.
- let align = match self.size_and_align_of(&base.meta, &field_layout)? {
- Some((_, align)) => align,
- None if offset == Size::ZERO => {
- // An extern type at offset 0, we fall back to its static alignment.
- // FIXME: Once we have made decisions for how to handle size and alignment
- // of `extern type`, this should be adapted. It is just a temporary hack
- // to get some code to work that probably ought to work.
- field_layout.align.abi
+ match self.size_and_align_of(&base.meta, &field_layout)? {
+ Some((_, align)) => (base.meta, offset.align_to(align)),
+ None => {
+ // For unsized types with an extern type tail we perform no adjustments.
+ // NOTE: keep this in sync with `PlaceRef::project_field` in the codegen backend.
+ assert!(matches!(base.meta, MemPlaceMeta::None));
+ (base.meta, offset)
}
- None => span_bug!(
- self.cur_span(),
- "cannot compute offset for extern type field at non-0 offset"
- ),
- };
- (base.meta, offset.align_to(align))
+ }
} else {
// base.meta could be present; we might be accessing a sized field of an unsized
// struct.
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 71db58f2d8b..ba1b8caa368 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -633,16 +633,6 @@ pub trait LintContext: Sized {
}
},
BuiltinLintDiagnostics::Normal => (),
- BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
- let (sugg, app) = match sess.source_map().span_to_snippet(span) {
- Ok(s) if is_global => {
- (format!("dyn ({})", s), Applicability::MachineApplicable)
- }
- Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
- Err(_) => ("dyn ".to_string(), Applicability::HasPlaceholders),
- };
- db.span_suggestion(span, "use `dyn`", sugg, app);
- }
BuiltinLintDiagnostics::AbsPathWithModule(span) => {
let (sugg, app) = match sess.source_map().span_to_snippet(span) {
Ok(ref s) => {
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index da1edcf6fe3..ed24b94e2fd 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -169,7 +169,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
if !(type_permits_lack_of_use || fn_warned || op_warned) {
- cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| lint.build("unused result").emit());
+ cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
+ lint.build(&format!("unused result of type `{}`", ty)).emit()
+ });
}
// Returns whether an error has been emitted (and thus another does not need to be later).
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 3f504d75dfc..e22c9c68de6 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -285,7 +285,6 @@ pub enum ExternDepSpec {
#[derive(PartialEq, Debug)]
pub enum BuiltinLintDiagnostics {
Normal,
- BareTraitObject(Span, /* is_global */ bool),
AbsPathWithModule(Span),
ProcMacroDeriveResolutionFallback(Span),
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 78e33544655..e2de9f12aaa 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -771,11 +771,24 @@ rustc_queries! {
desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
load_cached(tcx, id) {
- let typeck_results: Option> = tcx
- .on_disk_cache().as_ref()
- .and_then(|c| c.try_load_query_result(*tcx, id));
+ #[cfg(bootstrap)]
+ {
+ match match tcx.on_disk_cache().as_ref() {
+ Some(c) => c.try_load_query_result(*tcx, id),
+ None => None,
+ } {
+ Some(x) => Some(&*tcx.arena.alloc(x)),
+ None => None,
+ }
+ }
+ #[cfg(not(bootstrap))]
+ {
+ let typeck_results: Option> = tcx
+ .on_disk_cache().as_ref()
+ .and_then(|c| c.try_load_query_result(*tcx, id));
- typeck_results.map(|x| &*tcx.arena.alloc(x))
+ typeck_results.map(|x| &*tcx.arena.alloc(x))
+ }
}
}
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 558b1ce082e..8be95b2d95a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -68,6 +68,12 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
if body.source.promoted.is_some() {
return false;
}
+ // Avoid inlining into generators, since their `optimized_mir` is used for layout computation,
+ // which can create a cycle, even when no attempt is made to inline the function in the other
+ // direction.
+ if body.generator.is_some() {
+ return false;
+ }
let mut this = Inliner {
tcx,
@@ -202,14 +208,6 @@ impl<'tcx> Inliner<'tcx> {
if let Some(callee_def_id) = callee.def_id().as_local() {
let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
- // Avoid inlining into generators,
- // since their `optimized_mir` is used for layout computation, which can
- // create a cycle, even when no attempt is made to inline the function
- // in the other direction.
- if caller_body.generator.is_some() {
- return Err("local generator (query cycle avoidance)");
- }
-
// Avoid a cycle here by only using `instance_mir` only if we have
// a lower `HirId` than the callee. This ensures that the callee will
// not inline us. This trick only works without incremental compilation.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 516e301ec3a..618aa3fd002 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
(Ident::empty(), ItemKind::Use(tree))
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
- let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo)?;
+ let (ident, sig, generics, body) = self.parse_fn(attrs, fn_parse_mode, lo, vis)?;
(ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
@@ -1511,9 +1511,16 @@ impl<'a> Parser<'a> {
let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() {
let err = if self.check_fn_front_matter(false) {
+ let inherited_vis = Visibility {
+ span: rustc_span::DUMMY_SP,
+ kind: VisibilityKind::Inherited,
+ tokens: None,
+ };
// We use `parse_fn` to get a span for the function
let fn_parse_mode = FnParseMode { req_name: |_| true, req_body: true };
- if let Err(mut db) = self.parse_fn(&mut Vec::new(), fn_parse_mode, lo) {
+ if let Err(mut db) =
+ self.parse_fn(&mut Vec::new(), fn_parse_mode, lo, &inherited_vis)
+ {
db.delay_as_bug();
}
let mut err = self.struct_span_err(
@@ -1793,8 +1800,9 @@ impl<'a> Parser<'a> {
attrs: &mut Vec,
fn_parse_mode: FnParseMode,
sig_lo: Span,
+ vis: &Visibility,
) -> PResult<'a, (Ident, FnSig, Generics, Option>)> {
- let header = self.parse_fn_front_matter()?; // `const ... fn`
+ let header = self.parse_fn_front_matter(vis)?; // `const ... fn`
let ident = self.parse_ident()?; // `foo`
let mut generics = self.parse_generics()?; // `<'a, T, ...>`
let decl =
@@ -1903,12 +1911,15 @@ impl<'a> Parser<'a> {
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
/// up to and including the `fn` keyword. The formal grammar is:
///
- /// ```
+ /// ```text
/// Extern = "extern" StringLit? ;
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
/// FnFrontMatter = FnQual "fn" ;
/// ```
- pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
+ ///
+ /// `vis` represents the visibility that was already parsed, if any. Use
+ /// `Visibility::Inherited` when no visibility is known.
+ pub(super) fn parse_fn_front_matter(&mut self, orig_vis: &Visibility) -> PResult<'a, FnHeader> {
let sp_start = self.token.span;
let constness = self.parse_constness();
@@ -1934,51 +1945,94 @@ impl<'a> Parser<'a> {
Ok(false) => unreachable!(),
Err(mut err) => {
// Qualifier keywords ordering check
+ enum WrongKw {
+ Duplicated(Span),
+ Misplaced(Span),
+ }
- // This will allow the machine fix to directly place the keyword in the correct place
- let current_qual_sp = if self.check_keyword(kw::Const) {
- Some(async_start_sp)
+ // This will allow the machine fix to directly place the keyword in the correct place or to indicate
+ // that the keyword is already present and the second instance should be removed.
+ let wrong_kw = if self.check_keyword(kw::Const) {
+ match constness {
+ Const::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+ Const::No => Some(WrongKw::Misplaced(async_start_sp)),
+ }
} else if self.check_keyword(kw::Async) {
- Some(unsafe_start_sp)
+ match asyncness {
+ Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)),
+ Async::No => Some(WrongKw::Misplaced(unsafe_start_sp)),
+ }
} else if self.check_keyword(kw::Unsafe) {
- Some(ext_start_sp)
+ match unsafety {
+ Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
+ Unsafe::No => Some(WrongKw::Misplaced(ext_start_sp)),
+ }
} else {
None
};
- if let Some(current_qual_sp) = current_qual_sp {
- let current_qual_sp = current_qual_sp.to(self.prev_token.span);
- if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
- let invalid_qual_sp = self.token.uninterpolated_span();
- let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
+ // The keyword is already present, suggest removal of the second instance
+ if let Some(WrongKw::Duplicated(original_sp)) = wrong_kw {
+ let original_kw = self
+ .span_to_snippet(original_sp)
+ .expect("Span extracted directly from keyword should always work");
+
+ err.span_suggestion(
+ self.token.uninterpolated_span(),
+ &format!("`{}` already used earlier, remove this one", original_kw),
+ "".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .span_note(original_sp, &format!("`{}` first seen here", original_kw));
+ }
+ // The keyword has not been seen yet, suggest correct placement in the function front matter
+ else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
+ let correct_pos_sp = correct_pos_sp.to(self.prev_token.span);
+ if let Ok(current_qual) = self.span_to_snippet(correct_pos_sp) {
+ let misplaced_qual_sp = self.token.uninterpolated_span();
+ let misplaced_qual = self.span_to_snippet(misplaced_qual_sp).unwrap();
err.span_suggestion(
- current_qual_sp.to(invalid_qual_sp),
- &format!("`{}` must come before `{}`", invalid_qual, current_qual),
- format!("{} {}", invalid_qual, current_qual),
- Applicability::MachineApplicable,
- ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+ correct_pos_sp.to(misplaced_qual_sp),
+ &format!("`{}` must come before `{}`", misplaced_qual, current_qual),
+ format!("{} {}", misplaced_qual, current_qual),
+ Applicability::MachineApplicable,
+ ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
}
}
- // Recover incorrect visibility order such as `async pub`.
+ // Recover incorrect visibility order such as `async pub`
else if self.check_keyword(kw::Pub) {
let sp = sp_start.to(self.prev_token.span);
if let Ok(snippet) = self.span_to_snippet(sp) {
- let vis = match self.parse_visibility(FollowedByType::No) {
+ let current_vis = match self.parse_visibility(FollowedByType::No) {
Ok(v) => v,
Err(mut d) => {
d.cancel();
return Err(err);
}
};
- let vs = pprust::vis_to_string(&vis);
+ let vs = pprust::vis_to_string(¤t_vis);
let vs = vs.trim_end();
- err.span_suggestion(
- sp_start.to(self.prev_token.span),
- &format!("visibility `{}` must come before `{}`", vs, snippet),
- format!("{} {}", vs, snippet),
- Applicability::MachineApplicable,
- );
+
+ // There was no explicit visibility
+ if matches!(orig_vis.kind, VisibilityKind::Inherited) {
+ err.span_suggestion(
+ sp_start.to(self.prev_token.span),
+ &format!("visibility `{}` must come before `{}`", vs, snippet),
+ format!("{} {}", vs, snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ // There was an explicit visibility
+ else {
+ err.span_suggestion(
+ current_vis.span,
+ "there is already a visibility modifier, remove one",
+ "".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .span_note(orig_vis.span, "explicit visibility first seen here");
+ }
}
}
return Err(err);
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 9bfde0e3900..02a774ba129 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -474,7 +474,13 @@ impl<'a> Parser<'a> {
params: Vec,
recover_return_sign: RecoverReturnSign,
) -> PResult<'a, TyKind> {
- let ast::FnHeader { ext, unsafety, constness, asyncness } = self.parse_fn_front_matter()?;
+ let inherited_vis = rustc_ast::Visibility {
+ span: rustc_span::DUMMY_SP,
+ kind: rustc_ast::VisibilityKind::Inherited,
+ tokens: None,
+ };
+ let ast::FnHeader { ext, unsafety, constness, asyncness } =
+ self.parse_fn_front_matter(&inherited_vis)?;
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
let whole_span = lo.to(self.prev_token.span);
if let ast::Const::Yes(span) = constness {
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 23c3b5af262..8db706c3709 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -13,6 +13,7 @@ use crate::errors::{
};
use crate::middle::resolve_lifetime as rl;
use crate::require_c_abi_if_c_variadic;
+use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, ErrorReported, FatalError};
use rustc_hir as hir;
@@ -24,7 +25,8 @@ use rustc_hir::{GenericArg, GenericArgs};
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
-use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
+use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
+use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -2266,13 +2268,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
- self.ast_ty_to_ty_inner(ast_ty, false)
+ self.ast_ty_to_ty_inner(ast_ty, false, false)
+ }
+
+ /// Parses the programmer's textual representation of a type into our
+ /// internal notion of a type. This is meant to be used within a path.
+ pub fn ast_ty_to_ty_in_path(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+ self.ast_ty_to_ty_inner(ast_ty, false, true)
}
/// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait
/// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors.
#[tracing::instrument(level = "debug", skip(self))]
- fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool) -> Ty<'tcx> {
+ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
let tcx = self.tcx();
let result_ty = match ast_ty.kind {
@@ -2283,7 +2291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TyKind::Rptr(ref region, ref mt) => {
let r = self.ast_region_to_region(region, None);
debug!(?r);
- let t = self.ast_ty_to_ty_inner(mt.ty, true);
+ let t = self.ast_ty_to_ty_inner(mt.ty, true, false);
tcx.mk_ref(r, ty::TypeAndMut { ty: t, mutbl: mt.mutbl })
}
hir::TyKind::Never => tcx.types.never,
@@ -2302,6 +2310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
))
}
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
+ self.maybe_lint_bare_trait(ast_ty, in_path);
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
}
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
@@ -2329,7 +2338,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
debug!(?qself, ?segment);
- let ty = self.ast_ty_to_ty(qself);
+ let ty = self.ast_ty_to_ty_inner(qself, false, true);
let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
path.res
@@ -2586,4 +2595,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
Some(r)
}
+
+ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
+ let tcx = self.tcx();
+ if let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
+ self_ty.kind
+ {
+ let needs_bracket = in_path
+ && !tcx
+ .sess
+ .source_map()
+ .span_to_prev_source(self_ty.span)
+ .ok()
+ .map_or(false, |s| s.trim_end().ends_with('<'));
+
+ let is_global = poly_trait_ref.trait_ref.path.is_global();
+ let sugg = Vec::from_iter([
+ (
+ self_ty.span.shrink_to_lo(),
+ format!(
+ "{}dyn {}",
+ if needs_bracket { "<" } else { "" },
+ if is_global { "(" } else { "" },
+ ),
+ ),
+ (
+ self_ty.span.shrink_to_hi(),
+ format!(
+ "{}{}",
+ if is_global { ")" } else { "" },
+ if needs_bracket { ">" } else { "" },
+ ),
+ ),
+ ]);
+ if self_ty.span.edition() >= Edition::Edition2021 {
+ let msg = "trait objects must include the `dyn` keyword";
+ let label = "add `dyn` keyword before this trait";
+ rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg)
+ .multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable)
+ .emit();
+ } else {
+ let msg = "trait objects without an explicit `dyn` are deprecated";
+ tcx.struct_span_lint_hir(
+ BARE_TRAIT_OBJECTS,
+ self_ty.hir_id,
+ self_ty.span,
+ |lint| {
+ lint.build(msg)
+ .multipart_suggestion_verbose(
+ "use `dyn`",
+ sugg,
+ Applicability::MachineApplicable,
+ )
+ .emit()
+ },
+ );
+ }
+ }
+ }
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 738af9bfb8c..67630fd4e58 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -6,7 +6,6 @@ use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
-use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
@@ -14,7 +13,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, Node, QPath, TyKind};
+use rustc_hir::{ExprKind, GenericArg, Node, QPath};
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
use rustc_infer::infer::{InferOk, InferResult};
@@ -28,8 +27,6 @@ use rustc_middle::ty::{
Ty, UserType,
};
use rustc_session::lint;
-use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_span::edition::Edition;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{original_sp, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
@@ -855,7 +852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to be object-safe.
// We manually call `register_wf_obligation` in the success path
// below.
- (>::ast_ty_to_ty(self, qself), qself, segment)
+ (>::ast_ty_to_ty_in_path(self, qself), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
@@ -901,7 +898,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
if result.is_ok() {
- self.maybe_lint_bare_trait(qpath, hir_id, span);
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
}
@@ -914,56 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
}
- fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId, span: Span) {
- if let QPath::TypeRelative(self_ty, _) = qpath {
- if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
- self_ty.kind
- {
- let msg = "trait objects without an explicit `dyn` are deprecated";
- let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
- Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
- (format!("dyn ({})", s), Applicability::MachineApplicable)
- }
- Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
- Err(_) => ("dyn ".to_string(), Applicability::HasPlaceholders),
- };
- // Wrap in `<..>` if it isn't already.
- let sugg = match self.tcx.sess.source_map().span_to_snippet(span) {
- Ok(s) if s.starts_with('<') => sugg,
- _ => format!("<{}>", sugg),
- };
- let sugg_label = "use `dyn`";
- if self.sess().edition() >= Edition::Edition2021 {
- let mut err = rustc_errors::struct_span_err!(
- self.sess(),
- self_ty.span,
- E0782,
- "{}",
- msg,
- );
- err.span_suggestion(
- self_ty.span,
- sugg_label,
- sugg,
- Applicability::MachineApplicable,
- )
- .emit();
- } else {
- self.tcx.struct_span_lint_hir(
- BARE_TRAIT_OBJECTS,
- hir_id,
- self_ty.span,
- |lint| {
- let mut db = lint.build(msg);
- db.span_suggestion(self_ty.span, sugg_label, sugg, app);
- db.emit()
- },
- );
- }
- }
- }
- }
-
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
pub(in super::super) fn get_node_fn_decl(
&self,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index da1baa36d6e..67f77f14a6e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -123,6 +123,7 @@
#![feature(const_num_from_num)]
#![feature(const_ops)]
#![feature(const_option)]
+#![feature(const_option_ext)]
#![feature(const_pin)]
#![feature(const_replace)]
#![feature(const_ptr_is_null)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 015366ed490..8969c6f6171 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -589,12 +589,13 @@ impl Option {
#[must_use]
#[inline]
#[unstable(feature = "option_result_contains", issue = "62358")]
- pub fn contains(&self, x: &U) -> bool
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn contains(&self, x: &U) -> bool
where
- U: PartialEq,
+ U: ~const PartialEq,
{
match self {
- Some(y) => x == y,
+ Some(y) => x.eq(y),
None => false,
}
}
@@ -660,10 +661,14 @@ impl Option {
#[inline]
#[must_use]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_ref(self: Pin<&Self>) -> Option> {
- // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
- // which is pinned.
- unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_pin_ref(self: Pin<&Self>) -> Option> {
+ match Pin::get_ref(self).as_ref() {
+ // SAFETY: `x` is guaranteed to be pinned because it comes from `self`
+ // which is pinned.
+ Some(x) => unsafe { Some(Pin::new_unchecked(x)) },
+ None => None,
+ }
}
/// Converts from [Pin]<[&mut] Option\>
to Option<[Pin]<[&mut] T>>
.
@@ -672,10 +677,16 @@ impl Option {
#[inline]
#[must_use]
#[stable(feature = "pin", since = "1.33.0")]
- pub fn as_pin_mut(self: Pin<&mut Self>) -> Option> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_pin_mut(self: Pin<&mut Self>) -> Option> {
// SAFETY: `get_unchecked_mut` is never used to move the `Option` inside `self`.
// `x` is guaranteed to be pinned because it comes from `self` which is pinned.
- unsafe { Pin::get_unchecked_mut(self).as_mut().map(|x| Pin::new_unchecked(x)) }
+ unsafe {
+ match Pin::get_unchecked_mut(self).as_mut() {
+ Some(x) => Some(Pin::new_unchecked(x)),
+ None => None,
+ }
+ }
}
/////////////////////////////////////////////////////////////////////////
@@ -764,7 +775,11 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or(self, default: T) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or(self, default: T) -> T
+ where
+ T: ~const Drop,
+ {
match self {
Some(x) => x,
None => default,
@@ -782,7 +797,12 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or_else T>(self, f: F) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or_else(self, f: F) -> T
+ where
+ F: ~const FnOnce() -> T,
+ F: ~const Drop,
+ {
match self {
Some(x) => x,
None => f(),
@@ -812,7 +832,8 @@ impl Option {
#[inline]
#[track_caller]
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
- pub unsafe fn unwrap_unchecked(self) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
Some(val) => val,
@@ -842,7 +863,12 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map U>(self, f: F) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map(self, f: F) -> Option
+ where
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ {
match self {
Some(x) => Some(f(x)),
None => None,
@@ -866,7 +892,12 @@ impl Option {
/// ```
#[inline]
#[unstable(feature = "result_option_inspect", issue = "91345")]
- pub fn inspect(self, f: F) -> Self {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn inspect(self, f: F) -> Self
+ where
+ F: ~const FnOnce(&T),
+ F: ~const Drop,
+ {
if let Some(ref x) = self {
f(x);
}
@@ -894,7 +925,13 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or U>(self, default: U, f: F) -> U {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map_or(self, default: U, f: F) -> U
+ where
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ U: ~const Drop,
+ {
match self {
Some(t) => f(t),
None => default,
@@ -917,7 +954,14 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or_else U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn map_or_else(self, default: D, f: F) -> U
+ where
+ D: ~const FnOnce() -> U,
+ D: ~const Drop,
+ F: ~const FnOnce(T) -> U,
+ F: ~const Drop,
+ {
match self {
Some(t) => f(t),
None => default(),
@@ -947,7 +991,11 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok_or(self, err: E) -> Result {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn ok_or(self, err: E) -> Result
+ where
+ E: ~const Drop,
+ {
match self {
Some(v) => Ok(v),
None => Err(err),
@@ -972,7 +1020,12 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ok_or_else E>(self, err: F) -> Result {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn ok_or_else(self, err: F) -> Result
+ where
+ F: ~const FnOnce() -> E,
+ F: ~const Drop,
+ {
match self {
Some(v) => Ok(v),
None => Err(err()),
@@ -1049,7 +1102,12 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and(self, optb: Option) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn and(self, optb: Option) -> Option
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ {
match self {
Some(_) => optb,
None => None,
@@ -1074,7 +1132,12 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn and_then Option>(self, f: F) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn and_then(self, f: F) -> Option
+ where
+ F: ~const FnOnce(T) -> Option,
+ F: ~const Drop,
+ {
match self {
Some(x) => f(x),
None => None,
@@ -1107,7 +1170,13 @@ impl Option {
/// [`Some(t)`]: Some
#[inline]
#[stable(feature = "option_filter", since = "1.27.0")]
- pub fn filter bool>(self, predicate: P) -> Self {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn filter(self, predicate: P) -> Self
+ where
+ T: ~const Drop,
+ P: ~const FnOnce(&T) -> bool,
+ P: ~const Drop,
+ {
if let Some(x) = self {
if predicate(&x) {
return Some(x);
@@ -1145,9 +1214,13 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or(self, optb: Option) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn or(self, optb: Option) -> Option
+ where
+ T: ~const Drop,
+ {
match self {
- Some(_) => self,
+ Some(x) => Some(x),
None => optb,
}
}
@@ -1167,9 +1240,14 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn or_else Option>(self, f: F) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn or_else(self, f: F) -> Option
+ where
+ F: ~const FnOnce() -> Option,
+ F: ~const Drop,
+ {
match self {
- Some(_) => self,
+ Some(x) => Some(x),
None => f(),
}
}
@@ -1197,7 +1275,11 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "option_xor", since = "1.37.0")]
- pub fn xor(self, optb: Option) -> Option {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn xor(self, optb: Option) -> Option
+ where
+ T: ~const Drop,
+ {
match (self, optb) {
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
@@ -1231,7 +1313,11 @@ impl Option {
#[must_use = "if you intended to set a value, consider assignment instead"]
#[inline]
#[stable(feature = "option_insert", since = "1.53.0")]
- pub fn insert(&mut self, value: T) -> &mut T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn insert(&mut self, value: T) -> &mut T
+ where
+ T: ~const Drop,
+ {
*self = Some(value);
// SAFETY: the code above just filled the option
@@ -1260,8 +1346,18 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- pub fn get_or_insert(&mut self, value: T) -> &mut T {
- self.get_or_insert_with(|| value)
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert(&mut self, value: T) -> &mut T
+ where
+ T: ~const Drop,
+ {
+ if let None = *self {
+ *self = Some(value);
+ }
+
+ // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+ // variant in the code above.
+ unsafe { self.as_mut().unwrap_unchecked() }
}
/// Inserts the default value into the option if it is [`None`], then
@@ -1285,11 +1381,17 @@ impl Option {
/// ```
#[inline]
#[unstable(feature = "option_get_or_insert_default", issue = "82901")]
- pub fn get_or_insert_default(&mut self) -> &mut T
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert_default(&mut self) -> &mut T
where
- T: Default,
+ T: ~const Default,
{
- self.get_or_insert_with(Default::default)
+ #[rustc_allow_const_fn_unstable(const_fn_trait_bound)]
+ const fn default() -> T {
+ T::default()
+ }
+
+ self.get_or_insert_with(default)
}
/// Inserts a value computed from `f` into the option if it is [`None`],
@@ -1311,17 +1413,21 @@ impl Option {
/// ```
#[inline]
#[stable(feature = "option_entry", since = "1.20.0")]
- pub fn get_or_insert_with T>(&mut self, f: F) -> &mut T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn get_or_insert_with(&mut self, f: F) -> &mut T
+ where
+ F: ~const FnOnce() -> T,
+ F: ~const Drop,
+ {
if let None = *self {
- *self = Some(f());
+ // the compiler isn't smart enough to know that we are not dropping a `T`
+ // here and wants us to ensure `T` can be dropped at compile time.
+ mem::forget(mem::replace(self, Some(f())))
}
- match self {
- Some(v) => v,
- // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
- // variant in the code above.
- None => unsafe { hint::unreachable_unchecked() },
- }
+ // SAFETY: a `None` variant for `self` would have been replaced by a `Some`
+ // variant in the code above.
+ unsafe { self.as_mut().unwrap_unchecked() }
}
/////////////////////////////////////////////////////////////////////////
@@ -1391,7 +1497,12 @@ impl Option {
/// assert_eq!(x.zip(z), None);
/// ```
#[stable(feature = "option_zip_option", since = "1.46.0")]
- pub fn zip(self, other: Option) -> Option<(T, U)> {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn zip(self, other: Option) -> Option<(T, U)>
+ where
+ T: ~const Drop,
+ U: ~const Drop,
+ {
match (self, other) {
(Some(a), Some(b)) => Some((a, b)),
_ => None,
@@ -1427,11 +1538,18 @@ impl Option {
/// assert_eq!(x.zip_with(None, Point::new), None);
/// ```
#[unstable(feature = "option_zip", issue = "70086")]
- pub fn zip_with(self, other: Option, f: F) -> Option
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn zip_with(self, other: Option, f: F) -> Option
where
- F: FnOnce(T, U) -> R,
+ F: ~const FnOnce(T, U) -> R,
+ F: ~const Drop,
+ T: ~const Drop,
+ U: ~const Drop,
{
- Some(f(self?, other?))
+ match (self, other) {
+ (Some(a), Some(b)) => Some(f(a, b)),
+ _ => None,
+ }
}
}
@@ -1503,8 +1621,12 @@ impl Option<&mut T> {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "copied", since = "1.35.0")]
- pub fn copied(self) -> Option {
- self.map(|&mut t| t)
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn copied(self) -> Option {
+ match self {
+ Some(&mut t) => Some(t),
+ None => None,
+ }
}
}
@@ -1591,7 +1713,11 @@ impl Option {
/// [`FromStr`]: crate::str::FromStr
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn unwrap_or_default(self) -> T {
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn unwrap_or_default(self) -> T
+ where
+ T: ~const Default,
+ {
match self {
Some(x) => x,
None => Default::default(),
@@ -1615,8 +1741,15 @@ impl Option {
/// assert_eq!(x.as_deref(), None);
/// ```
#[stable(feature = "option_deref", since = "1.40.0")]
- pub fn as_deref(&self) -> Option<&T::Target> {
- self.as_ref().map(|t| t.deref())
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_deref(&self) -> Option<&T::Target>
+ where
+ T: ~const Deref,
+ {
+ match self.as_ref() {
+ Some(t) => Some(t.deref()),
+ None => None,
+ }
}
}
@@ -1636,8 +1769,15 @@ impl Option {
/// }), Some("HEY".to_owned().as_mut_str()));
/// ```
#[stable(feature = "option_deref", since = "1.40.0")]
- pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
- self.as_mut().map(|t| t.deref_mut())
+ #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+ pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+ where
+ T: ~const DerefMut,
+ {
+ match self.as_mut() {
+ Some(t) => Some(t.deref_mut()),
+ None => None,
+ }
}
}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index dacb33619f8..21562acf3d7 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -70,8 +70,10 @@
#![feature(portable_simd)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
+#![feature(option_result_contains)]
#![feature(unsized_tuple_coercion)]
#![feature(const_option)]
+#![feature(const_option_ext)]
#![feature(const_result)]
#![feature(integer_atomics)]
#![feature(int_roundings)]
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index cd07d6c52c2..da692461261 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -86,17 +86,49 @@ fn test_and() {
let x: Option = None;
assert_eq!(x.and(Some(2)), None);
assert_eq!(x.and(None::), None);
+
+ const FOO: Option = Some(1);
+ const A: Option = FOO.and(Some(2));
+ const B: Option = FOO.and(None);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option = None;
+ const C: Option = BAR.and(Some(2));
+ const D: Option = BAR.and(None);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
}
#[test]
fn test_and_then() {
+ const fn plus_one(x: isize) -> Option {
+ Some(x + 1)
+ }
+
+ const fn none(_: isize) -> Option {
+ None
+ }
+
let x: Option = Some(1);
- assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
- assert_eq!(x.and_then(|_| None::), None);
+ assert_eq!(x.and_then(plus_one), Some(2));
+ assert_eq!(x.and_then(none), None);
let x: Option = None;
- assert_eq!(x.and_then(|x| Some(x + 1)), None);
- assert_eq!(x.and_then(|_| None::), None);
+ assert_eq!(x.and_then(plus_one), None);
+ assert_eq!(x.and_then(none), None);
+
+ const FOO: Option = Some(1);
+ const A: Option = FOO.and_then(plus_one);
+ const B: Option = FOO.and_then(none);
+ assert_eq!(A, Some(2));
+ assert_eq!(B, None);
+
+ const BAR: Option = None;
+ const C: Option = BAR.and_then(plus_one);
+ const D: Option = BAR.and_then(none);
+ assert_eq!(C, None);
+ assert_eq!(D, None);
}
#[test]
@@ -108,17 +140,49 @@ fn test_or() {
let x: Option = None;
assert_eq!(x.or(Some(2)), Some(2));
assert_eq!(x.or(None), None);
+
+ const FOO: Option = Some(1);
+ const A: Option = FOO.or(Some(2));
+ const B: Option = FOO.or(None);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option = None;
+ const C: Option = BAR.or(Some(2));
+ const D: Option = BAR.or(None);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
}
#[test]
fn test_or_else() {
+ const fn two() -> Option {
+ Some(2)
+ }
+
+ const fn none() -> Option {
+ None
+ }
+
let x: Option = Some(1);
- assert_eq!(x.or_else(|| Some(2)), Some(1));
- assert_eq!(x.or_else(|| None), Some(1));
+ assert_eq!(x.or_else(two), Some(1));
+ assert_eq!(x.or_else(none), Some(1));
let x: Option = None;
- assert_eq!(x.or_else(|| Some(2)), Some(2));
- assert_eq!(x.or_else(|| None), None);
+ assert_eq!(x.or_else(two), Some(2));
+ assert_eq!(x.or_else(none), None);
+
+ const FOO: Option = Some(1);
+ const A: Option = FOO.or_else(two);
+ const B: Option = FOO.or_else(none);
+ assert_eq!(A, Some(1));
+ assert_eq!(B, Some(1));
+
+ const BAR: Option = None;
+ const C: Option = BAR.or_else(two);
+ const D: Option = BAR.or_else(none);
+ assert_eq!(C, Some(2));
+ assert_eq!(D, None);
}
#[test]
@@ -149,15 +213,29 @@ fn test_unwrap_or() {
let x: Option = None;
assert_eq!(x.unwrap_or(2), 2);
+
+ const A: isize = Some(1).unwrap_or(2);
+ const B: isize = None.unwrap_or(2);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
}
#[test]
fn test_unwrap_or_else() {
+ const fn two() -> isize {
+ 2
+ }
+
let x: Option = Some(1);
- assert_eq!(x.unwrap_or_else(|| 2), 1);
+ assert_eq!(x.unwrap_or_else(two), 1);
let x: Option = None;
- assert_eq!(x.unwrap_or_else(|| 2), 2);
+ assert_eq!(x.unwrap_or_else(two), 2);
+
+ const A: isize = Some(1).unwrap_or_else(two);
+ const B: isize = None.unwrap_or_else(two);
+ assert_eq!(A, 1);
+ assert_eq!(B, 2);
}
#[test]
diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
index d19229aabad..84ccf25ef75 100644
--- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
+++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
@@ -20,21 +20,16 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1
let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
- let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
- let mut _8: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
- let mut _9: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
+ let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
scope 1 {
debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
}
- scope 2 (inlined String::new) { // at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- let mut _6: std::vec::Vec; // in scope 2 at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- scope 3 (inlined Vec::::new) { // at $DIR/generator-drop-cleanup.rs:11:18: 11:31
- }
- }
bb0: {
- _9 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
- switchInt(move _9) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+ switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
}
bb1: {
diff --git a/src/test/rustdoc-ui/display-output.rs b/src/test/rustdoc-ui/display-output.rs
index 30b32c511b5..c40d99c9d4c 100644
--- a/src/test/rustdoc-ui/display-output.rs
+++ b/src/test/rustdoc-ui/display-output.rs
@@ -10,6 +10,6 @@
/// #![warn(unused)]
/// let x = 12;
///
-/// fn foo(x: &std::fmt::Display) {}
+/// fn foo(x: &dyn std::fmt::Display) {}
/// ```
pub fn foo() {}
diff --git a/src/test/rustdoc-ui/display-output.stdout b/src/test/rustdoc-ui/display-output.stdout
index f76dec1c850..41c1f41f2cf 100644
--- a/src/test/rustdoc-ui/display-output.stdout
+++ b/src/test/rustdoc-ui/display-output.stdout
@@ -5,16 +5,6 @@ test $DIR/display-output.rs - foo (line 9) ... ok
successes:
---- $DIR/display-output.rs - foo (line 9) stdout ----
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/display-output.rs:13:12
- |
-LL | fn foo(x: &std::fmt::Display) {}
- | ^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::fmt::Display`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
- = note: for more information, see
-
warning: unused variable: `x`
--> $DIR/display-output.rs:11:5
|
@@ -31,13 +21,13 @@ LL | #![warn(unused)]
warning: unused variable: `x`
--> $DIR/display-output.rs:13:8
|
-LL | fn foo(x: &std::fmt::Display) {}
+LL | fn foo(x: &dyn std::fmt::Display) {}
| ^ help: if this is intentional, prefix it with an underscore: `_x`
warning: function is never used: `foo`
--> $DIR/display-output.rs:13:4
|
-LL | fn foo(x: &std::fmt::Display) {}
+LL | fn foo(x: &dyn std::fmt::Display) {}
| ^^^
|
note: the lint level is defined here
@@ -47,7 +37,7 @@ LL | #![warn(unused)]
| ^^^^^^
= note: `#[warn(dead_code)]` implied by `#[warn(unused)]`
-warning: 4 warnings emitted
+warning: 3 warnings emitted
diff --git a/src/test/ui/closures/closure-expected.stderr b/src/test/ui/closures/closure-expected.stderr
index 8b38d5ff459..7ffe3c1ef95 100644
--- a/src/test/ui/closures/closure-expected.stderr
+++ b/src/test/ui/closures/closure-expected.stderr
@@ -11,8 +11,8 @@ LL | let y = x.or_else(4);
note: required by a bound in `Option::::or_else`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn or_else Option>(self, f: F) -> Option {
- | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::::or_else`
+LL | F: ~const FnOnce() -> Option,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::::or_else`
error: aborting due to previous error
diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
index 24db2725347..883348eb98c 100644
--- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr
+++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr
@@ -10,8 +10,8 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
note: required by a bound in `Option::::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
-LL | pub fn map U>(self, f: F) -> Option {
- | ^^^^^^^^^^^^^^ required by this bound in `Option::::map`
+LL | F: ~const FnOnce(T) -> U,
+ | ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::::map`
error: aborting due to previous error
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
index ae8863c567d..e12e07a28e7 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.rs
@@ -12,8 +12,6 @@ fn b() {
//~^ ERROR expected trait, found constant `BAR`
//~| ERROR expected trait, found constant `BAR`
//~| ERROR type provided when a constant was expected
- //~| WARN trait objects without an explicit `dyn` are deprecated
- //~| WARN this is accepted in the current edition
}
fn c() {
foo::<3 + 3>(); //~ ERROR expressions must be enclosed in braces
diff --git a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
index 380c17c8e62..d9bcc523b1f 100644
--- a/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
+++ b/src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces.stderr
@@ -10,7 +10,7 @@ LL | foo::<{ BAR + 3 }>();
| + +
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:19:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:17:11
|
LL | foo::<3 + 3>();
| ^^^^^
@@ -21,7 +21,7 @@ LL | foo::<{ 3 + 3 }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:22:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:20:15
|
LL | foo::();
| ^ expected one of `,` or `>`
@@ -32,7 +32,7 @@ LL | foo::<{ BAR - 3 }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:25:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:23:15
|
LL | foo::();
| ^ expected one of `,` or `>`
@@ -43,7 +43,7 @@ LL | foo::<{ BAR - BAR }>();
| + +
error: expressions must be enclosed in braces to be used as const generic arguments
- --> $DIR/const-expression-suggest-missing-braces.rs:28:11
+ --> $DIR/const-expression-suggest-missing-braces.rs:26:11
|
LL | foo::<100 - BAR>();
| ^^^^^^^^^
@@ -54,7 +54,7 @@ LL | foo::<{ 100 - BAR }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:31:19
+ --> $DIR/const-expression-suggest-missing-braces.rs:29:19
|
LL | foo::()>();
| ^ expected one of `,` or `>`
@@ -65,7 +65,7 @@ LL | foo::<{ bar() }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:34:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:32:21
|
LL | foo::()>();
| ^ expected one of `,` or `>`
@@ -76,7 +76,7 @@ LL | foo::<{ bar::() }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:37:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:35:21
|
LL | foo::() + BAR>();
| ^ expected one of `,` or `>`
@@ -87,7 +87,7 @@ LL | foo::<{ bar::() + BAR }>();
| + +
error: expected one of `,` or `>`, found `(`
- --> $DIR/const-expression-suggest-missing-braces.rs:40:21
+ --> $DIR/const-expression-suggest-missing-braces.rs:38:21
|
LL | foo::() - BAR>();
| ^ expected one of `,` or `>`
@@ -98,7 +98,7 @@ LL | foo::<{ bar::() - BAR }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:43:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:41:15
|
LL | foo::()>();
| ^ expected one of `,` or `>`
@@ -109,7 +109,7 @@ LL | foo::<{ BAR - bar::() }>();
| + +
error: expected one of `,` or `>`, found `-`
- --> $DIR/const-expression-suggest-missing-braces.rs:46:15
+ --> $DIR/const-expression-suggest-missing-braces.rs:44:15
|
LL | foo::()>();
| ^ expected one of `,` or `>`
@@ -131,23 +131,13 @@ error[E0404]: expected trait, found constant `BAR`
LL | foo::();
| ^^^ not a trait
-warning: trait objects without an explicit `dyn` are deprecated
- --> $DIR/const-expression-suggest-missing-braces.rs:11:11
- |
-LL | foo::();
- | ^^^^^^^^^ help: use `dyn`: `dyn BAR + BAR`
- |
- = note: `#[warn(bare_trait_objects)]` on by default
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see
-
error[E0747]: type provided when a constant was expected
--> $DIR/const-expression-suggest-missing-braces.rs:11:11
|
LL | foo::();
| ^^^^^^^^^
-error: aborting due to 14 previous errors; 1 warning emitted
+error: aborting due to 14 previous errors
Some errors have detailed explanations: E0404, E0747.
For more information about an error, try `rustc --explain E0404`.
diff --git a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
new file mode 100644
index 00000000000..d5576ebfd02
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
@@ -0,0 +1,58 @@
+// run-pass
+//
+// Test that we can handle unsized types with an extern type tail part.
+// Regression test for issue #91827.
+
+#![feature(const_ptr_offset_from)]
+#![feature(const_slice_from_raw_parts)]
+#![feature(extern_types)]
+
+use std::ptr::addr_of;
+
+extern "C" {
+ type Opaque;
+}
+
+unsafe impl Sync for Opaque {}
+
+#[repr(C)]
+pub struct List {
+ len: usize,
+ data: [T; 0],
+ tail: Opaque,
+}
+
+#[repr(C)]
+pub struct ListImpl {
+ len: usize,
+ data: [T; N],
+}
+
+impl List {
+ const fn as_slice(&self) -> &[T] {
+ unsafe { std::slice::from_raw_parts(self.data.as_ptr(), self.len) }
+ }
+}
+
+impl ListImpl {
+ const fn as_list(&self) -> &List {
+ unsafe { std::mem::transmute(self) }
+ }
+}
+
+pub static A: ListImpl = ListImpl {
+ len: 3,
+ data: [5, 6, 7],
+};
+pub static A_REF: &'static List = A.as_list();
+pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
+
+const fn tail_offset(list: &List) -> isize {
+ unsafe { (addr_of!(list.tail) as *const u8).offset_from(list as *const List as *const u8) }
+}
+
+fn main() {
+ assert_eq!(A_REF.as_slice(), &[5, 6, 7]);
+ // Check that interpreter and code generation agree about the position of the tail field.
+ assert_eq!(A_TAIL_OFFSET, tail_offset(A_REF));
+}
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs
index 1b6bcfbb9fc..609a5b0de6b 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.rs
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs
@@ -32,6 +32,8 @@ type G = dyn 'static + (Send)::AssocTy;
// Recovery should not apply in this context.
type H = Fn(u8) -> (u8)::Output;
//~^ ERROR ambiguous associated type
+//~| WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this is accepted in the current edition
macro_rules! ty {
($ty: ty) => ($ty::AssocTy);
diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
index 0e2fdf9f6c2..11514a28b2c 100644
--- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr
@@ -41,13 +41,13 @@ LL | type G = dyn 'static + (Send)::AssocTy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `::AssocTy`
error: missing angle brackets in associated item path
- --> $DIR/bad-assoc-ty.rs:44:10
+ --> $DIR/bad-assoc-ty.rs:46:10
|
LL | type I = ty!()::AssocTy;
| ^^^^^^^^^^^^^^ help: try: `::AssocTy`
error: missing angle brackets in associated item path
- --> $DIR/bad-assoc-ty.rs:37:19
+ --> $DIR/bad-assoc-ty.rs:39:19
|
LL | ($ty: ty) => ($ty::AssocTy);
| ^^^^^^^^^^^^ help: try: `<$ty>::AssocTy`
@@ -99,6 +99,20 @@ error[E0223]: ambiguous associated type
LL | type G = dyn 'static + (Send)::AssocTy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy`
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/bad-assoc-ty.rs:33:10
+ |
+LL | type H = Fn(u8) -> (u8)::Output;
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+ = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+ = note: for more information, see
+help: use `dyn`
+ |
+LL | type H = (u8)>::Output;
+ | ++++ +
+
error[E0223]: ambiguous associated type
--> $DIR/bad-assoc-ty.rs:33:10
|
@@ -106,7 +120,7 @@ LL | type H = Fn(u8) -> (u8)::Output;
| ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output`
error[E0223]: ambiguous associated type
- --> $DIR/bad-assoc-ty.rs:37:19
+ --> $DIR/bad-assoc-ty.rs:39:19
|
LL | ($ty: ty) => ($ty::AssocTy);
| ^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy`
@@ -117,13 +131,13 @@ LL | type J = ty!(u8);
= note: this error originates in the macro `ty` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0223]: ambiguous associated type
- --> $DIR/bad-assoc-ty.rs:44:10
+ --> $DIR/bad-assoc-ty.rs:46:10
|
LL | type I = ty!()::AssocTy;
| ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::AssocTy`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:49:13
+ --> $DIR/bad-assoc-ty.rs:51:13
|
LL | fn foo>(x: X) {}
| ^ ^ not allowed in type signatures
@@ -136,7 +150,7 @@ LL | fn foo, T>(x: X) {}
| ~ ~ +++
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:52:34
+ --> $DIR/bad-assoc-ty.rs:54:34
|
LL | fn bar(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
@@ -147,7 +161,7 @@ LL | fn bar(_: F) where F: Fn() -> T {}
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:55:19
+ --> $DIR/bad-assoc-ty.rs:57:19
|
LL | fn baz _>(_: F) {}
| ^ not allowed in type signatures
@@ -158,7 +172,7 @@ LL | fn baz T, T>(_: F) {}
| ~+++
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:58:33
+ --> $DIR/bad-assoc-ty.rs:60:33
|
LL | struct L(F) where F: Fn() -> _;
| ^ not allowed in type signatures
@@ -169,7 +183,7 @@ LL | struct L(F) where F: Fn() -> T;
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
- --> $DIR/bad-assoc-ty.rs:60:30
+ --> $DIR/bad-assoc-ty.rs:62:30
|
LL | struct M where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -180,7 +194,7 @@ LL | struct M where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for enums
- --> $DIR/bad-assoc-ty.rs:64:28
+ --> $DIR/bad-assoc-ty.rs:66:28
|
LL | enum N where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -191,7 +205,7 @@ LL | enum N where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for unions
- --> $DIR/bad-assoc-ty.rs:69:29
+ --> $DIR/bad-assoc-ty.rs:71:29
|
LL | union O where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -202,7 +216,7 @@ LL | union O where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for traits
- --> $DIR/bad-assoc-ty.rs:74:29
+ --> $DIR/bad-assoc-ty.rs:76:29
|
LL | trait P where F: Fn() -> _ {
| ^ not allowed in type signatures
@@ -213,7 +227,7 @@ LL | trait P where F: Fn() -> T {
| +++ ~
error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
- --> $DIR/bad-assoc-ty.rs:79:38
+ --> $DIR/bad-assoc-ty.rs:81:38
|
LL | fn foo(_: F) where F: Fn() -> _ {}
| ^ not allowed in type signatures
@@ -223,7 +237,7 @@ help: use type parameters instead
LL | fn foo(_: F) where F: Fn() -> T {}
| +++ ~
-error: aborting due to 28 previous errors
+error: aborting due to 28 previous errors; 1 warning emitted
Some errors have detailed explanations: E0121, E0223.
For more information about an error, try `rustc --explain E0121`.
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
index 23ca36b71e0..a074b5fa5f7 100644
--- a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.rs
@@ -6,6 +6,14 @@ fn function(x: &SomeTrait, y: Box) {
//~| WARN this is accepted in the current edition
//~| ERROR trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
+ //~| ERROR trait objects without an explicit `dyn` are deprecated
+ //~| WARN this is accepted in the current edition
let _x: &SomeTrait = todo!();
//~^ ERROR trait objects without an explicit `dyn` are deprecated
//~| WARN this is accepted in the current edition
diff --git a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
index c9bb08cf35c..b8e4942dfef 100644
--- a/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
+++ b/src/test/ui/dyn-keyword/dyn-2018-edition-lint.stderr
@@ -2,7 +2,7 @@ error: trait objects without an explicit `dyn` are deprecated
--> $DIR/dyn-2018-edition-lint.rs:4:17
|
LL | fn function(x: &SomeTrait, y: Box) {
- | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+ | ^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/dyn-2018-edition-lint.rs:2:8
@@ -11,24 +11,95 @@ LL | #[deny(bare_trait_objects)]
| ^^^^^^^^^^^^^^^^^^
= warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
= note: for more information, see
+help: use `dyn`
+ |
+LL - fn function(x: &SomeTrait, y: Box) {
+LL + fn function(x: &dyn SomeTrait, y: Box) {
+ |
error: trait objects without an explicit `dyn` are deprecated
--> $DIR/dyn-2018-edition-lint.rs:4:35
|
LL | fn function(x: &SomeTrait, y: Box