Auto merge of #133703 - matthiaskrgr:rollup-fwlw0mc, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #132974 (Properly pass linker arguments that contain commas)
 - #133403 (Make `adjust_fulfillment_errors` work with `HostEffectPredicate` and `const_conditions`)
 - #133482 (Only error raw lifetime followed by `\'` in edition 2021+)
 - #133595 (Do not emit `missing_doc_code_examples` rustdoc lint on module and a few other items)
 - #133669 (Move some functions out of const_swap feature gate)
 - #133674 (Fix chaining `carrying_add`s)
 - #133691 (Check let source before suggesting annotation)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-12-01 19:49:19 +00:00
commit 5e1440ae51
69 changed files with 707 additions and 336 deletions

View file

@ -1386,7 +1386,7 @@ fn link_sanitizer_runtime(
let filename = format!("rustc{channel}_rt.{name}");
let path = find_sanitizer_runtime(sess, &filename);
let rpath = path.to_str().expect("non-utf8 component in path");
linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_args(&["-rpath", rpath]);
linker.link_dylib_by_name(&filename, false, true);
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
@ -2210,7 +2210,7 @@ fn add_rpath_args(
is_like_osx: sess.target.is_like_osx,
linker_is_gnu: sess.target.linker_flavor.is_gnu(),
};
cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
cmd.link_args(&rpath::get_rpath_linker_args(&rpath_config));
}
}

View file

@ -24,6 +24,9 @@ use super::command::Command;
use super::symbol_export;
use crate::errors;
#[cfg(test)]
mod tests;
/// Disables non-English messages from localized linkers.
/// Such messages may cause issues with text encoding on Windows (#35785)
/// and prevent inspection of linker output in case of errors, which we occasionally do.
@ -178,23 +181,42 @@ fn verbatim_args<L: Linker + ?Sized>(
}
l
}
/// Arguments for the underlying linker.
/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
fn link_args<L: Linker + ?Sized>(
l: &mut L,
args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>,
) -> &mut L {
let args = args.into_iter();
if !l.is_cc() {
verbatim_args(l, args);
} else if args.len() != 0 {
// FIXME: Support arguments with commas, see `rpaths_to_flags` for the example.
let mut combined_arg = OsString::from("-Wl");
for arg in args {
/// Add underlying linker arguments to C compiler command, by wrapping them in
/// `-Wl` or `-Xlinker`.
fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
let mut combined_arg = OsString::from("-Wl");
for arg in args {
// If the argument itself contains a comma, we need to emit it
// as `-Xlinker`, otherwise we can use `-Wl`.
if arg.as_ref().as_encoded_bytes().contains(&b',') {
// Emit current `-Wl` argument, if any has been built.
if combined_arg != OsStr::new("-Wl") {
cmd.arg(combined_arg);
// Begin next `-Wl` argument.
combined_arg = OsString::from("-Wl");
}
// Emit `-Xlinker` argument.
cmd.arg("-Xlinker");
cmd.arg(arg);
} else {
// Append to `-Wl` argument.
combined_arg.push(",");
combined_arg.push(arg);
}
l.cmd().arg(combined_arg);
}
// Emit final `-Wl` argument.
if combined_arg != OsStr::new("-Wl") {
cmd.arg(combined_arg);
}
}
/// Arguments for the underlying linker.
/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
if !l.is_cc() {
verbatim_args(l, args);
} else {
convert_link_args_to_cc_args(l.cmd(), args);
}
l
}
@ -224,7 +246,7 @@ macro_rules! generate_arg_methods {
verbatim_args(self, iter::once(arg))
}
#[allow(unused)]
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self {
pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
link_args(self, args)
}
#[allow(unused)]

View file

@ -0,0 +1,32 @@
use super::*;
#[test]
fn test_rpaths_to_args() {
let mut cmd = Command::new("foo");
convert_link_args_to_cc_args(&mut cmd, &["-rpath", "path1", "-rpath", "path2"]);
assert_eq!(cmd.get_args(), [OsStr::new("-Wl,-rpath,path1,-rpath,path2")]);
}
#[test]
fn test_xlinker() {
let mut cmd = Command::new("foo");
convert_link_args_to_cc_args(&mut cmd, &[
"arg1",
"arg2",
"arg3,with,comma",
"arg4,with,comma",
"arg5",
"arg6,with,comma",
]);
assert_eq!(cmd.get_args(), [
OsStr::new("-Wl,arg1,arg2"),
OsStr::new("-Xlinker"),
OsStr::new("arg3,with,comma"),
OsStr::new("-Xlinker"),
OsStr::new("arg4,with,comma"),
OsStr::new("-Wl,arg5"),
OsStr::new("-Xlinker"),
OsStr::new("arg6,with,comma"),
]);
}

View file

@ -13,39 +13,27 @@ pub(super) struct RPathConfig<'a> {
pub linker_is_gnu: bool,
}
pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
debug!("preparing the RPATH!");
let rpaths = get_rpaths(config);
let mut flags = rpaths_to_flags(rpaths);
let mut args = Vec::with_capacity(rpaths.len() * 2); // the minimum needed capacity
for rpath in rpaths {
args.push("-rpath".into());
args.push(rpath);
}
if config.linker_is_gnu {
// Use DT_RUNPATH instead of DT_RPATH if available
flags.push("-Wl,--enable-new-dtags".into());
args.push("--enable-new-dtags".into());
// Set DF_ORIGIN for substitute $ORIGIN
flags.push("-Wl,-z,origin".into());
args.push("-z".into());
args.push("origin".into());
}
flags
}
fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
for rpath in rpaths {
if rpath.to_string_lossy().contains(',') {
ret.push("-Wl,-rpath".into());
ret.push("-Xlinker".into());
ret.push(rpath);
} else {
let mut single_arg = OsString::from("-Wl,-rpath,");
single_arg.push(rpath);
ret.push(single_arg);
}
}
ret
args
}
fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {

View file

@ -1,13 +1,4 @@
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use super::{RPathConfig, get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
#[test]
fn test_rpaths_to_flags() {
let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
}
use super::*;
#[test]
fn test_minimize1() {
@ -69,15 +60,3 @@ fn test_rpath_relative_issue_119571() {
// Should not panic when lib only contains filename.
let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
}
#[test]
fn test_xlinker() {
let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
assert_eq!(args, vec![
OsString::from("-Wl,-rpath,a/normal/path"),
OsString::from("-Wl,-rpath"),
OsString::from("-Xlinker"),
OsString::from("a,comma,path")
]);
}

View file

@ -4,7 +4,7 @@ use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
use rustc_hir::def::{self, CtorKind, Namespace, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, LangItem};
use rustc_hir::{self as hir, HirId, LangItem};
use rustc_hir_analysis::autoderef::Autoderef;
use rustc_infer::infer;
use rustc_infer::traits::{self, Obligation, ObligationCause, ObligationCauseCode};
@ -428,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Ty<'tcx> {
let (fn_sig, def_id) = match *callee_ty.kind() {
ty::FnDef(def_id, args) => {
self.enforce_context_effects(call_expr.span, def_id, args);
self.enforce_context_effects(Some(call_expr.hir_id), call_expr.span, def_id, args);
let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);
// Unit testing: function items annotated with
@ -837,6 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[tracing::instrument(level = "debug", skip(self, span))]
pub(super) fn enforce_context_effects(
&self,
call_hir_id: Option<HirId>,
span: Span,
callee_did: DefId,
callee_args: GenericArgsRef<'tcx>,
@ -867,10 +868,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.tcx.is_conditionally_const(callee_did) {
let q = self.tcx.const_conditions(callee_did);
// FIXME(const_trait_impl): Use this span with a better cause code.
for (cond, _) in q.instantiate(self.tcx, callee_args) {
for (idx, (cond, pred_span)) in
q.instantiate(self.tcx, callee_args).into_iter().enumerate()
{
let cause = self.cause(
span,
if let Some(hir_id) = call_hir_id {
ObligationCauseCode::HostEffectInExpr(callee_did, pred_span, hir_id, idx)
} else {
ObligationCauseCode::WhereClause(callee_did, pred_span)
},
);
self.register_predicate(Obligation::new(
self.tcx,
self.misc(span),
cause,
self.param_env,
cond.to_host_effect_clause(self.tcx, host),
));

View file

@ -705,7 +705,8 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) -> Self::Result {
// For a local, try suggest annotating the type if it's missing.
if let None = local.ty
if let hir::LocalSource::Normal = local.source
&& let None = local.ty
&& let Some(ty) = self.fcx.typeck_results.borrow().node_type_opt(local.hir_id)
&& let Some(vid) = self.fcx.root_vid(ty)
&& self.reachable_vids.contains(&vid)

View file

@ -185,7 +185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
method: MethodCallee<'tcx>,
) {
self.enforce_context_effects(span, method.def_id, method.args);
self.enforce_context_effects(Some(hir_id), span, method.def_id, method.args);
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
self.write_args(hir_id, method.args);
}
@ -263,6 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
Adjust::Deref(Some(overloaded_deref)) => {
self.enforce_context_effects(
None,
expr.span,
overloaded_deref.method_call(self.tcx),
self.tcx.mk_args(&[a.target.into()]),

View file

@ -11,26 +11,56 @@ use rustc_trait_selection::traits;
use crate::FnCtxt;
enum ClauseFlavor {
/// Predicate comes from `predicates_of`.
Where,
/// Predicate comes from `const_conditions`.
Const,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn adjust_fulfillment_error_for_expr_obligation(
&self,
error: &mut traits::FulfillmentError<'tcx>,
) -> bool {
let ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) =
*error.obligation.cause.code().peel_derives()
else {
return false;
let (def_id, hir_id, idx, flavor) = match *error.obligation.cause.code().peel_derives() {
ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) => {
(def_id, hir_id, idx, ClauseFlavor::Where)
}
ObligationCauseCode::HostEffectInExpr(def_id, _, hir_id, idx) => {
(def_id, hir_id, idx, ClauseFlavor::Const)
}
_ => return false,
};
let Some(uninstantiated_pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
.predicates
.into_iter()
.nth(idx)
else {
return false;
let uninstantiated_pred = match flavor {
ClauseFlavor::Where => {
if let Some(pred) = self
.tcx
.predicates_of(def_id)
.instantiate_identity(self.tcx)
.predicates
.into_iter()
.nth(idx)
{
pred
} else {
return false;
}
}
ClauseFlavor::Const => {
if let Some((pred, _)) = self
.tcx
.const_conditions(def_id)
.instantiate_identity(self.tcx)
.into_iter()
.nth(idx)
{
pred.to_host_effect_clause(self.tcx, ty::BoundConstness::Maybe)
} else {
return false;
}
}
};
let generics = self.tcx.generics_of(def_id);
@ -39,6 +69,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::ClauseKind::Trait(pred) => {
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
}
ty::ClauseKind::HostEffect(pred) => {
(pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
}
ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
ty::ClauseKind::ConstArgHasType(arg, ty) => (vec![ty.into(), arg.into()], None),
ty::ClauseKind::ConstEvaluatable(e) => (vec![e.into()], None),
@ -94,39 +127,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
}
let (expr, qpath) = match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => {
if self.closure_span_overlaps_error(error, expr.span) {
return false;
match self.tcx.hir_node(hir_id) {
hir::Node::Expr(expr) => self.point_at_expr_if_possible(
error,
def_id,
expr,
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
),
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => {
for param in [
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, &qpath) {
return true;
}
}
let qpath =
if let hir::ExprKind::Path(qpath) = expr.kind { Some(qpath) } else { None };
(Some(&expr.kind), qpath)
}
hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => (None, Some(*qpath)),
_ => return false,
};
if let Some(qpath) = qpath {
// Prefer pointing at the turbofished arg that corresponds to the
// self type of the failing predicate over anything else.
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_path_if_possible(error, def_id, param, &qpath)
{
return true;
false
}
if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Call(callee, args),
hir_id: call_hir_id,
span: call_span,
..
}) = self.tcx.parent_hir_node(hir_id)
&& callee.hir_id == hir_id
{
if self.closure_span_overlaps_error(error, *call_span) {
return false;
_ => false,
}
}
fn point_at_expr_if_possible(
&self,
error: &mut traits::FulfillmentError<'tcx>,
callee_def_id: DefId,
expr: &'tcx hir::Expr<'tcx>,
predicate_self_type_to_point_at: Option<ty::GenericArg<'tcx>>,
param_to_point_at: Option<ty::GenericArg<'tcx>>,
fallback_param_to_point_at: Option<ty::GenericArg<'tcx>>,
self_param_to_point_at: Option<ty::GenericArg<'tcx>>,
) -> bool {
if self.closure_span_overlaps_error(error, expr.span) {
return false;
}
match expr.kind {
hir::ExprKind::Call(
hir::Expr { kind: hir::ExprKind::Path(qpath), span: callee_span, .. },
args,
) => {
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
{
return true;
}
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
@ -135,32 +191,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if self.blame_specific_arg_if_possible(
error,
def_id,
callee_def_id,
param,
*call_hir_id,
callee.span,
expr.hir_id,
*callee_span,
None,
args,
) {
return true;
}
}
}
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, &qpath) {
return true;
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
return true;
}
}
}
}
hir::ExprKind::Path(qpath) => {
// If the parent is an call, then process this as a call.
//
// This is because the `WhereClauseInExpr` obligations come from
// the well-formedness of the *path* expression, but we care to
// point at the call expression (namely, its args).
if let hir::Node::Expr(
call_expr @ hir::Expr { kind: hir::ExprKind::Call(callee, ..), .. },
) = self.tcx.parent_hir_node(expr.hir_id)
&& callee.hir_id == expr.hir_id
{
return self.point_at_expr_if_possible(
error,
callee_def_id,
call_expr,
predicate_self_type_to_point_at,
param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
);
}
// Otherwise, just try to point at path components.
match expr {
Some(hir::ExprKind::MethodCall(segment, receiver, args, ..)) => {
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_generic_if_possible(error, def_id, param, segment)
&& self.point_at_path_if_possible(error, callee_def_id, param, &qpath)
{
return true;
}
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, callee_def_id, param, &qpath) {
return true;
}
}
}
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
if let Some(param) = predicate_self_type_to_point_at
&& self.point_at_generic_if_possible(error, callee_def_id, param, segment)
{
// HACK: This is not correct, since `predicate_self_type_to_point_at` might
// not actually correspond to the receiver of the method call. But we
@ -170,7 +262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error.obligation.cause.map_code(|parent_code| {
ObligationCauseCode::FunctionArg {
arg_hir_id: receiver.hir_id,
call_hir_id: hir_id,
call_hir_id: expr.hir_id,
parent_code,
}
});
@ -183,9 +275,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if self.blame_specific_arg_if_possible(
error,
def_id,
callee_def_id,
param,
hir_id,
expr.hir_id,
segment.ident.span,
Some(receiver),
args,
@ -194,7 +286,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if let Some(param_to_point_at) = param_to_point_at
&& self.point_at_generic_if_possible(error, def_id, param_to_point_at, segment)
&& self.point_at_generic_if_possible(
error,
callee_def_id,
param_to_point_at,
segment,
)
{
return true;
}
@ -208,17 +305,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true;
}
}
Some(hir::ExprKind::Struct(qpath, fields, ..)) => {
hir::ExprKind::Struct(qpath, fields, ..) => {
if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
self.typeck_results.borrow().qpath_res(qpath, hir_id)
self.typeck_results.borrow().qpath_res(qpath, expr.hir_id)
{
for param in
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
let refined_expr =
self.point_at_field_if_possible(def_id, param, variant_def_id, fields);
let refined_expr = self.point_at_field_if_possible(
callee_def_id,
param,
variant_def_id,
fields,
);
match refined_expr {
None => {}
@ -242,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, qpath) {
if self.point_at_path_if_possible(error, callee_def_id, param, qpath) {
return true;
}
}
@ -525,7 +626,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &'tcx hir::Expr<'tcx>,
) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
match obligation_cause_code {
traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _) => {
traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _)
| ObligationCauseCode::HostEffectInExpr(..) => {
// This is the "root"; we assume that the `expr` is already pointing here.
// Therefore, we return `Ok` so that this `expr` can be refined further.
Ok(expr)

View file

@ -296,7 +296,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
};
*deref = OverloadedDeref { mutbl, span: deref.span };
self.enforce_context_effects(expr.span, method.def_id, method.args);
self.enforce_context_effects(None, expr.span, method.def_id, method.args);
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// This helps avoid accidental drops.
if inside_union

View file

@ -707,17 +707,7 @@ impl Cursor<'_> {
self.bump();
self.bump();
self.eat_while(is_id_continue);
match self.first() {
'\'' => {
// Check if after skipping literal contents we've met a closing
// single quote (which means that user attempted to create a
// string with single quotes).
self.bump();
let kind = Char { terminated: true };
return Literal { kind, suffix_start: self.pos_within_token() };
}
_ => return RawLifetime,
}
return RawLifetime;
}
// Either a lifetime or a character literal with

View file

@ -204,6 +204,10 @@ pub enum ObligationCauseCode<'tcx> {
/// list of the item.
WhereClauseInExpr(DefId, Span, HirId, usize),
/// Like `WhereClauseinExpr`, but indexes into the `const_conditions`
/// rather than the `predicates_of`.
HostEffectInExpr(DefId, Span, HirId, usize),
/// A type like `&'a T` is WF only if `T: 'a`.
ReferenceOutlivesReferent(Ty<'tcx>),

View file

@ -300,6 +300,26 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
let prefix_span = self.mk_sp(start, ident_start);
if prefix_span.at_least_rust_2021() {
// If the raw lifetime is followed by \' then treat it a normal
// lifetime followed by a \', which is to interpret it as a character
// literal. In this case, it's always an invalid character literal
// since the literal must necessarily have >3 characters (r#...) inside
// of it, which is invalid.
if self.cursor.as_str().starts_with('\'') {
let lit_span = self.mk_sp(start, self.pos + BytePos(1));
let contents = self.str_from_to(start + BytePos(1), self.pos);
emit_unescape_error(
self.dcx(),
contents,
lit_span,
lit_span,
Mode::Char,
0..contents.len(),
EscapeError::MoreThanOneChar,
)
.expect("expected error");
}
let span = self.mk_sp(start, self.pos);
let lifetime_name_without_tick =
@ -371,8 +391,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret),
rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent),
rustc_lexer::TokenKind::Unknown
| rustc_lexer::TokenKind::InvalidIdent => {
rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => {
// Don't emit diagnostics for sequences of the same invalid token
if swallow_next_invalid > 0 {
swallow_next_invalid -= 1;

View file

@ -2803,6 +2803,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
ObligationCauseCode::WhereClause(item_def_id, span)
| ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
| ObligationCauseCode::HostEffectInExpr(item_def_id, span, ..)
if !span.is_dummy() =>
{
if let ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, pos) = &cause_code {
@ -2966,7 +2967,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
err.help(help);
}
}
ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) => {
ObligationCauseCode::WhereClause(..)
| ObligationCauseCode::WhereClauseInExpr(..)
| ObligationCauseCode::HostEffectInExpr(..) => {
// We hold the `DefId` of the item introducing the obligation, but displaying it
// doesn't add user usable information. It always point at an associated item.
}

View file

@ -2354,7 +2354,7 @@ macro_rules! uint_impl {
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
let (a, b) = self.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as $SelfT);
(c, b || d)
(c, b | d)
}
/// Calculates `self` + `rhs` with a signed `rhs`.

View file

@ -1009,6 +1009,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
#[rustc_diagnostic_item = "ptr_swap"]
#[rustc_const_stable_indirect]
pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
// Give ourselves some scratch space to work with.
// We do not have to worry about drops: `MaybeUninit` does nothing when dropped.
@ -1069,7 +1070,7 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
/// ```
#[inline]
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")]
#[rustc_diagnostic_item = "ptr_swap_nonoverlapping"]
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
#[allow(unused)]
@ -1129,7 +1130,6 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
/// LLVM can vectorize this (at least it can for the power-of-two-sized types
/// `swap_nonoverlapping` tries to use) so no need to manually SIMD it.
#[inline]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, count: usize) {
let x = x.cast::<MaybeUninit<T>>();
let y = y.cast::<MaybeUninit<T>>();

View file

@ -959,7 +959,7 @@ impl<T> [T] {
/// [`swap`]: slice::swap
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
#[unstable(feature = "slice_swap_unchecked", issue = "88539")]
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
#[rustc_const_unstable(feature = "slice_swap_unchecked", issue = "88539")]
pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) {
assert_unsafe_precondition!(
check_library_ub,

View file

@ -18,6 +18,7 @@
#![feature(const_eval_select)]
#![feature(const_heap)]
#![feature(const_nonnull_new)]
#![feature(const_swap)]
#![feature(const_trait_impl)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]

View file

@ -897,6 +897,25 @@ fn test_const_copy() {
};
}
#[test]
fn test_const_swap() {
const {
let mut ptr1 = &1;
let mut ptr2 = &666;
// Swap ptr1 and ptr2, bytewise. `swap` does not take a count
// so the best we can do is use an array.
type T = [u8; mem::size_of::<&i32>()];
unsafe {
ptr::swap(ptr::from_mut(&mut ptr1).cast::<T>(), ptr::from_mut(&mut ptr2).cast::<T>());
}
// Make sure they still work.
assert!(*ptr1 == 666);
assert!(*ptr2 == 1);
};
}
#[test]
fn test_null_array_as_slice() {
let arr: *mut [u8; 4] = null_mut();

View file

@ -47,6 +47,10 @@ It can be enabled using:
#![deny(rustdoc::missing_doc_code_examples)]
```
It is not emitted for items that cannot be instantiated/called such as fields, variants, modules,
associated trait/impl items, impl blocks, statics and constants.
It is also not emitted for foreign items, aliases, extern crates and imports.
## Extensions to the `#[doc]` attribute
These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler

View file

@ -60,8 +60,6 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
item.kind,
clean::StructFieldItem(_)
| clean::VariantItem(_)
| clean::AssocConstItem(..)
| clean::AssocTypeItem(..)
| clean::TypeAliasItem(_)
| clean::StaticItem(_)
| clean::ConstantItem(..)
@ -69,6 +67,15 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
| clean::ImportItem(_)
| clean::PrimitiveItem(_)
| clean::KeywordItem
| clean::ModuleItem(_)
| clean::TraitAliasItem(_)
| clean::ForeignFunctionItem(..)
| clean::ForeignStaticItem(..)
| clean::ForeignTypeItem
| clean::AssocConstItem(..)
| clean::AssocTypeItem(..)
| clean::TyAssocConstItem(..)
| clean::TyAssocTypeItem(..)
// check for trait impl
| clean::ImplItem(box clean::Impl { trait_: Some(_), .. })
)

View file

@ -0,0 +1,33 @@
//@ only-x86_64
//@ assembly-output: emit-asm
//@ compile-flags: --crate-type=lib -O -C target-cpu=x86-64-v4
//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel
#![no_std]
#![feature(bigint_helper_methods)]
// This checks that the `carrying_add` implementation successfully chains, to catch
// issues like <https://github.com/rust-lang/rust/issues/85532#issuecomment-2495119815>
// This forces the ABI to avoid the windows-vs-linux ABI differences.
// CHECK-LABEL: bigint_chain_carrying_add:
#[no_mangle]
pub unsafe extern "sysv64" fn bigint_chain_carrying_add(
dest: *mut u64,
src1: *const u64,
src2: *const u64,
n: usize,
mut carry: bool,
) -> bool {
// CHECK: mov [[TEMP:r..]], qword ptr [rsi + 8*[[IND:r..]] + 8]
// CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 8]
// CHECK: mov qword ptr [rdi + 8*[[IND]] + 8], [[TEMP]]
// CHECK: mov [[TEMP]], qword ptr [rsi + 8*[[IND]] + 16]
// CHECK: adc [[TEMP]], qword ptr [rdx + 8*[[IND]] + 16]
// CHECK: mov qword ptr [rdi + 8*[[IND]] + 16], [[TEMP]]
for i in 0..n {
(*dest.add(i), carry) = u64::carrying_add(*src1.add(i), *src2.add(i), carry);
}
carry
}

View file

@ -1 +1 @@
{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":2,"with_examples":1}}
{"$DIR/doc-examples-json.rs":{"total":3,"with_docs":2,"total_examples":1,"with_examples":1}}

View file

@ -1,7 +1,7 @@
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% |
| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 33.3% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 4 | 100.0% | 1 | 25.0% |
| Total | 4 | 100.0% | 1 | 33.3% |
+-------------------------------------+------------+------------+------------+------------+

View file

@ -1 +1 @@
{"$DIR/json.rs":{"total":17,"with_docs":12,"total_examples":15,"with_examples":6}}
{"$DIR/json.rs":{"total":17,"with_docs":12,"total_examples":13,"with_examples":6}}

View file

@ -4,7 +4,6 @@
#![feature(rustdoc_missing_doc_code_examples)]
//~^ WARN
//~^^ WARN
#![warn(missing_docs)]
#![warn(rustdoc::missing_doc_code_examples)]

View file

@ -4,19 +4,20 @@ warning: missing documentation for the crate
LL | / #![feature(rustdoc_missing_doc_code_examples)]
LL | |
LL | |
LL | | #![warn(missing_docs)]
... |
LL | |
LL | | pub fn foo() {}
| |_______________^
|
note: the lint level is defined here
--> $DIR/check.rs:9:9
--> $DIR/check.rs:8:9
|
LL | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: missing documentation for a function
--> $DIR/check.rs:13:1
--> $DIR/check.rs:12:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^
@ -26,34 +27,23 @@ warning: no documentation found for this crate's top-level module
= help: The following guide may be of use:
https://doc.rust-lang.org/$CHANNEL/rustdoc/how-to-write-documentation.html
note: the lint level is defined here
--> $DIR/check.rs:11:9
--> $DIR/check.rs:10:9
|
LL | #![warn(rustdoc::all)]
| ^^^^^^^^^^^^
= note: `#[warn(rustdoc::missing_crate_level_docs)]` implied by `#[warn(rustdoc::all)]`
warning: missing code example in this documentation
--> $DIR/check.rs:5:1
--> $DIR/check.rs:12:1
|
LL | / #![feature(rustdoc_missing_doc_code_examples)]
LL | |
LL | |
... |
LL | |
LL | | pub fn foo() {}
| |_______________^
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/check.rs:10:9
--> $DIR/check.rs:9:9
|
LL | #![warn(rustdoc::missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: missing code example in this documentation
--> $DIR/check.rs:13:1
|
LL | pub fn foo() {}
| ^^^^^^^^^^^^^^^
warning: 5 warnings emitted
warning: 4 warnings emitted

View file

@ -1,4 +1,4 @@
#![feature(rustdoc_missing_doc_code_examples)] //~ ERROR missing code example in this documentation
#![feature(rustdoc_missing_doc_code_examples)]
#![deny(rustdoc::missing_doc_code_examples)]
/// Some docs.
@ -6,7 +6,6 @@
pub struct Foo;
/// And then, the princess died.
//~^ ERROR missing code example in this documentation
pub mod foo {
/// Or maybe not because she saved herself!
//~^ ERROR missing code example in this documentation

View file

@ -1,14 +1,8 @@
error: missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:1:1
--> $DIR/doc-without-codeblock.rs:10:5
|
LL | / #![feature(rustdoc_missing_doc_code_examples)]
LL | | #![deny(rustdoc::missing_doc_code_examples)]
LL | |
LL | | /// Some docs.
... |
LL | | }
LL | | }
| |_^
LL | /// Or maybe not because she saved herself!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/doc-without-codeblock.rs:2:9
@ -16,23 +10,11 @@ note: the lint level is defined here
LL | #![deny(rustdoc::missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:8:1
|
LL | /// And then, the princess died.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:11:5
|
LL | /// Or maybe not because she saved herself!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:4:1
|
LL | /// Some docs.
| ^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

View file

@ -17,7 +17,7 @@ pub fn test() {
}
#[allow(missing_docs)]
pub mod module1 { //~ ERROR
pub mod module1 {
}
#[allow(rustdoc::missing_doc_code_examples)]

View file

@ -1,8 +1,8 @@
error: missing code example in this documentation
--> $DIR/lint-missing-doc-code-example.rs:20:1
--> $DIR/lint-missing-doc-code-example.rs:38:3
|
LL | pub mod module1 {
| ^^^^^^^^^^^^^^^
LL | /// doc
| ^^^^^^^
|
note: the lint level is defined here
--> $DIR/lint-missing-doc-code-example.rs:3:9
@ -10,12 +10,6 @@ note: the lint level is defined here
LL | #![deny(rustdoc::missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing code example in this documentation
--> $DIR/lint-missing-doc-code-example.rs:38:3
|
LL | /// doc
| ^^^^^^^
error: missing code example in this documentation
--> $DIR/lint-missing-doc-code-example.rs:50:1
|
@ -34,5 +28,5 @@ error: missing code example in this documentation
LL | /// Doc
| ^^^^^^^
error: aborting due to 5 previous errors
error: aborting due to 4 previous errors

View file

@ -1 +1 @@
{"$DIR/show-coverage-json.rs":{"total":2,"with_docs":1,"total_examples":2,"with_examples":1}}
{"$DIR/show-coverage-json.rs":{"total":2,"with_docs":1,"total_examples":1,"with_examples":1}}

View file

@ -1,7 +1,7 @@
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
| ...ests/rustdoc-ui/show-coverage.rs | 1 | 50.0% | 1 | 50.0% |
| ...ests/rustdoc-ui/show-coverage.rs | 1 | 50.0% | 1 | 100.0% |
+-------------------------------------+------------+------------+------------+------------+
| Total | 1 | 50.0% | 1 | 50.0% |
| Total | 1 | 50.0% | 1 | 100.0% |
+-------------------------------------+------------+------------+------------+------------+

View file

@ -1,8 +1,16 @@
error[E0277]: the trait bound `UnconstDrop: const Destruct` is not satisfied
--> $DIR/const-block-const-bound.rs:18:9
--> $DIR/const-block-const-bound.rs:18:11
|
LL | f(UnconstDrop);
| ^^^^^^^^^^^^^^
| - ^^^^^^^^^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `f`
--> $DIR/const-block-const-bound.rs:8:15
|
LL | const fn f<T: ~const Destruct>(x: T) {}
| ^^^^^^ required by this bound in `f`
error: aborting due to 1 previous error

View file

@ -2,13 +2,13 @@ error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:17:38
|
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
| ^^^^^^
| ^
error[E0277]: the trait bound `T: const Tr` is not satisfied
--> $DIR/constifconst-call-in-const-position.rs:18:9
|
LL | [0; T::a()]
| ^^^^^^
| ^
error: aborting due to 2 previous errors

View file

@ -121,34 +121,89 @@ LL | T: ~const FnMut<()> + ~const Destruct,
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:70:24
--> $DIR/fn_trait_refs.rs:70:32
|
LL | let test_one = test_fn(one);
| ^^^^^^^^^^^^
| ------- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `test_fn`
--> $DIR/fn_trait_refs.rs:35:24
|
LL | const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
| ------- required by a bound in this function
LL | where
LL | T: ~const Fn<()> + ~const Destruct,
| ^^^^^^ required by this bound in `test_fn`
error[E0277]: the trait bound `fn() -> i32 {two}: const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:73:24
--> $DIR/fn_trait_refs.rs:73:36
|
LL | let test_two = test_fn_mut(two);
| ^^^^^^^^^^^^^^^^
| ----------- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `test_fn_mut`
--> $DIR/fn_trait_refs.rs:49:27
|
LL | const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
| ----------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `test_fn_mut`
error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:39:9
--> $DIR/fn_trait_refs.rs:39:19
|
LL | tester_fn(&f),
| ^^^^^^^^^^^^^
| --------- ^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `tester_fn`
--> $DIR/fn_trait_refs.rs:14:24
|
LL | const fn tester_fn<T>(f: T) -> T::Output
| --------- required by a bound in this function
LL | where
LL | T: ~const Fn<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn`
error[E0277]: the trait bound `&T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:41:9
--> $DIR/fn_trait_refs.rs:41:23
|
LL | tester_fn_mut(&f),
| ^^^^^^^^^^^^^^^^^
| ------------- ^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `tester_fn_mut`
--> $DIR/fn_trait_refs.rs:21:27
|
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
| ------------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn_mut`
error[E0277]: the trait bound `&mut T: ~const Destruct` is not satisfied
--> $DIR/fn_trait_refs.rs:53:9
--> $DIR/fn_trait_refs.rs:53:23
|
LL | tester_fn_mut(&mut f),
| ^^^^^^^^^^^^^^^^^^^^^
| ------------- ^^^^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `tester_fn_mut`
--> $DIR/fn_trait_refs.rs:21:27
|
LL | const fn tester_fn_mut<T>(mut f: T) -> T::Output
| ------------- required by a bound in this function
LL | where
LL | T: ~const FnMut<()> + ~const Destruct,
| ^^^^^^ required by this bound in `tester_fn_mut`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/fn_trait_refs.rs:16:5

View file

@ -1,7 +1,7 @@
//@ compile-flags: -Z ui-testing=no
#![feature(const_swap)]
#![feature(const_swap_nonoverlapping)]
use std::{
mem::{self, MaybeUninit},
ptr,

View file

@ -13,10 +13,18 @@ LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruc
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied
--> $DIR/normalize-tait-in-const.rs:33:5
--> $DIR/normalize-tait-in-const.rs:33:19
|
LL | with_positive(foo);
| ^^^^^^^^^^^^^^^^^^
| ------------- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `with_positive`
--> $DIR/normalize-tait-in-const.rs:26:62
|
LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
| ^^^^^^ required by this bound in `with_positive`
error[E0015]: cannot call non-const closure in constant functions
--> $DIR/normalize-tait-in-const.rs:27:5

View file

@ -1,5 +1,5 @@
error: character literal may only contain one codepoint
--> $DIR/immediately-followed-by-lt.rs:11:4
--> $DIR/immediately-followed-by-lt.rs:15:4
|
LL | w!('r#long'id);
| ^^^^^^^^

View file

@ -1,4 +1,8 @@
//@ edition: 2021
//@ revisions: e2015 e2021
//@[e2021] edition: 2021
//@[e2015] edition: 2015
//@[e2015] check-pass
// Make sure we reject the case where a raw lifetime is immediately followed by another
// lifetime. This reserves a modest amount of space for changing lexing to, for example,
@ -9,6 +13,6 @@ macro_rules! w {
}
w!('r#long'id);
//~^ ERROR character literal may only contain one codepoint
//[e2021]~^ ERROR character literal may only contain one codepoint
fn main() {}

View file

@ -0,0 +1,17 @@
//@ run-rustfix
#![allow(unused)]
#![deny(dependency_on_unit_never_type_fallback)]
fn foo<T: Default>() -> Result<T, ()> {
Err(())
}
fn test() -> Result<(), ()> {
//~^ ERROR this function depends on never type fallback being `()`
//~| WARN this was previously accepted by the compiler but is being phased out
_ = foo::<()>()?;
Ok(())
}
fn main() {}

View file

@ -0,0 +1,17 @@
//@ run-rustfix
#![allow(unused)]
#![deny(dependency_on_unit_never_type_fallback)]
fn foo<T: Default>() -> Result<T, ()> {
Err(())
}
fn test() -> Result<(), ()> {
//~^ ERROR this function depends on never type fallback being `()`
//~| WARN this was previously accepted by the compiler but is being phased out
_ = foo()?;
Ok(())
}
fn main() {}

View file

@ -0,0 +1,26 @@
error: this function depends on never type fallback being `()`
--> $DIR/lint-breaking-2024-assign-underscore.rs:10:1
|
LL | fn test() -> Result<(), ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in Rust 2024 and in a future release in all editions!
= note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
= help: specify the types explicitly
note: in edition 2024, the requirement `!: Default` will fail
--> $DIR/lint-breaking-2024-assign-underscore.rs:13:9
|
LL | _ = foo()?;
| ^^^^^
note: the lint level is defined here
--> $DIR/lint-breaking-2024-assign-underscore.rs:4:9
|
LL | #![deny(dependency_on_unit_never_type_fallback)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use `()` annotations to avoid fallback changes
|
LL | _ = foo::<()>()?;
| ++++++
error: aborting due to 1 previous error

View file

@ -2,13 +2,13 @@ error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not sati
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:23:5
|
LL | T::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
error[E0277]: the trait bound `<T as Trait>::Assoc<U>: ~const Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail-2.rs:25:5
|
LL | <T as Trait>::Assoc::<U>::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -2,13 +2,13 @@ error[E0277]: the trait bound `T: ~const Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:16:5
|
LL | T::Assoc::func();
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^
error[E0277]: the trait bound `T: ~const Trait` is not satisfied
--> $DIR/assoc-type-const-bound-usage-fail.rs:18:5
|
LL | <T as Trait>::Assoc::func();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): ~const Bar` is not satisfied
--> $DIR/call-const-closure.rs:17:15
--> $DIR/call-const-closure.rs:17:18
|
LL | (const || ().foo())();
| ^^^^^^^^
| ^^^
error: aborting due to 1 previous error

View file

@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: const Foo` is not satisfied
--> $DIR/call-const-in-tilde-const.rs:9:13
|
LL | const { T::foo() }
| ^^^^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -2,7 +2,7 @@ error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
--> $DIR/call-const-trait-method-fail.rs:26:5
|
LL | a.plus(b)
| ^^^^^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -1,8 +1,16 @@
error[E0277]: the trait bound `S: const Foo` is not satisfied
--> $DIR/call-generic-method-nonconst.rs:24:22
--> $DIR/call-generic-method-nonconst.rs:24:34
|
LL | pub const EQ: bool = equals_self(&S);
| ^^^^^^^^^^^^^^^
| ----------- ^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `equals_self`
--> $DIR/call-generic-method-nonconst.rs:17:25
|
LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
| ^^^^^^ required by this bound in `equals_self`
error: aborting due to 1 previous error

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
--> $DIR/const-default-method-bodies.rs:25:5
--> $DIR/const-default-method-bodies.rs:25:18
|
LL | NonConstImpl.a();
| ^^^^^^^^^^^^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -1,8 +1,16 @@
error[E0277]: the trait bound `Foo<E>: ~const Destruct` is not satisfied
--> $DIR/const-drop-bound.rs:23:5
--> $DIR/const-drop-bound.rs:23:9
|
LL | foo(res)
| ^^^^^^^^
| --- ^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `foo`
--> $DIR/const-drop-bound.rs:9:61
|
LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
| ^^^^^^ required by this bound in `foo`
error: aborting due to 1 previous error

View file

@ -1,12 +1,14 @@
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
--> $DIR/const-drop-fail-2.rs:31:15
--> $DIR/const-drop-fail-2.rs:31:23
|
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| _______________^
LL | |
LL | | ConstDropImplWithBounds(PhantomData)
LL | | );
| |_^
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error: aborting due to 1 previous error

View file

@ -1,12 +1,14 @@
error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: const Destruct` is not satisfied
--> $DIR/const-drop-fail-2.rs:31:15
--> $DIR/const-drop-fail-2.rs:31:23
|
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| _______________^
LL | |
LL | | ConstDropImplWithBounds(PhantomData)
LL | | );
| |_^
LL | const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `check`
--> $DIR/const-drop-fail-2.rs:21:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error: aborting due to 1 previous error

View file

@ -1,31 +1,32 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:27:23
--> $DIR/const-drop-fail.rs:32:5
|
LL | const _: () = check($exp);
| ^^^^^^^^^^^
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | / check_all! {
LL | | NonTrivialDrop,
LL | | ConstImplWithDropGlue(NonTrivialDrop),
LL | | }
| |_- in this macro invocation
LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
= note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:27:23
--> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ^^^^^^^^^^^
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | / check_all! {
LL | | NonTrivialDrop,
LL | | ConstImplWithDropGlue(NonTrivialDrop),
LL | | }
| |_- in this macro invocation
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
= note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors

View file

@ -25,14 +25,14 @@ const fn check<T: ~const Destruct>(_: T) {}
macro_rules! check_all {
($($exp:expr),*$(,)?) => {$(
const _: () = check($exp);
//~^ ERROR the trait bound `NonTrivialDrop: const Destruct` is not satisfied
//~| ERROR the trait bound `NonTrivialDrop: const Destruct` is not satisfied
)*};
}
check_all! {
NonTrivialDrop,
//~^ ERROR the trait bound `NonTrivialDrop: const Destruct` is not satisfied
ConstImplWithDropGlue(NonTrivialDrop),
//~^ ERROR the trait bound `NonTrivialDrop: const Destruct` is not satisfied
}
fn main() {}

View file

@ -1,31 +1,32 @@
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:27:23
--> $DIR/const-drop-fail.rs:32:5
|
LL | const _: () = check($exp);
| ^^^^^^^^^^^
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | / check_all! {
LL | | NonTrivialDrop,
LL | | ConstImplWithDropGlue(NonTrivialDrop),
LL | | }
| |_- in this macro invocation
LL | NonTrivialDrop,
| ^^^^^^^^^^^^^^
|
= note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error[E0277]: the trait bound `NonTrivialDrop: const Destruct` is not satisfied
--> $DIR/const-drop-fail.rs:27:23
--> $DIR/const-drop-fail.rs:34:5
|
LL | const _: () = check($exp);
| ^^^^^^^^^^^
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | / check_all! {
LL | | NonTrivialDrop,
LL | | ConstImplWithDropGlue(NonTrivialDrop),
LL | | }
| |_- in this macro invocation
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
= note: this error originates in the macro `check_all` (in Nightly builds, run with -Z macro-backtrace for more info)
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:23:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^ required by this bound in `check`
error: aborting due to 2 previous errors

View file

@ -1,14 +1,22 @@
error[E0277]: the trait bound `(): const Foo` is not satisfied
--> $DIR/const-opaque.rs:31:18
--> $DIR/const-opaque.rs:31:22
|
LL | let opaque = bar(());
| ^^^^^^^
| --- ^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `bar`
--> $DIR/const-opaque.rs:26:17
|
LL | const fn bar<T: ~const Foo>(t: T) -> impl ~const Foo {
| ^^^^^^ required by this bound in `bar`
error[E0277]: the trait bound `(): const Foo` is not satisfied
--> $DIR/const-opaque.rs:33:5
--> $DIR/const-opaque.rs:33:12
|
LL | opaque.method();
| ^^^^^^^^^^^^^^^
| ^^^^^^
error: aborting due to 2 previous errors

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
--> $DIR/cross-crate.rs:19:5
--> $DIR/cross-crate.rs:19:14
|
LL | NonConst.func();
| ^^^^^^^^^^^^^^^
| ^^^^
error: aborting due to 1 previous error

View file

@ -1,8 +1,14 @@
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
--> $DIR/default-method-body-is-const-body-checking.rs:12:9
--> $DIR/default-method-body-is-const-body-checking.rs:12:15
|
LL | foo::<()>();
| ^^^^^^^^^^^
| ^^
|
note: required by a bound in `foo`
--> $DIR/default-method-body-is-const-body-checking.rs:7:28
|
LL | const fn foo<T>() where T: ~const Tr {}
| ^^^^^^ required by this bound in `foo`
error: aborting due to 1 previous error

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:9
--> $DIR/default-method-body-is-const-same-trait-ck.rs:9:12
|
LL | ().a()
| ^^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -1,8 +1,16 @@
error[E0277]: the trait bound `(): ~const Foo` is not satisfied
--> $DIR/minicore-fn-fail.rs:19:5
--> $DIR/minicore-fn-fail.rs:19:19
|
LL | call_indirect(&foo::<()>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| ------------- ^^^^^^^^^^
| |
| required by a bound introduced by this call
|
note: required by a bound in `call_indirect`
--> $DIR/minicore-fn-fail.rs:11:27
|
LL | const fn call_indirect<T: ~const Fn()>(t: &T) { t() }
| ^^^^^^ required by this bound in `call_indirect`
error: aborting due to 1 previous error

View file

@ -27,10 +27,10 @@ LL | trait Bar {
| ^^^
error[E0277]: the trait bound `(): const Bar` is not satisfied
--> $DIR/no-explicit-const-params.rs:24:5
--> $DIR/no-explicit-const-params.rs:24:6
|
LL | <() as Bar<false>>::bar();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^
error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
--> $DIR/no-explicit-const-params.rs:15:5

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: ~const A` is not satisfied
--> $DIR/specializing-constness-2.rs:27:5
--> $DIR/specializing-constness-2.rs:27:6
|
LL | <T as A>::a();
| ^^^^^^^^^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -11,10 +11,10 @@ LL | trait Bar: ~const Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
--> $DIR/super-traits-fail-2.rs:20:5
--> $DIR/super-traits-fail-2.rs:20:7
|
LL | x.a();
| ^^^^^
| ^
error: aborting due to 2 previous errors

View file

@ -1,8 +1,8 @@
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
--> $DIR/super-traits-fail-2.rs:20:5
--> $DIR/super-traits-fail-2.rs:20:7
|
LL | x.a();
| ^^^^^
| ^
error: aborting due to 1 previous error

View file

@ -25,10 +25,10 @@ LL | const fn foo<T: ~const Bar>(x: &T) {
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0277]: the trait bound `T: ~const Foo` is not satisfied
--> $DIR/super-traits-fail-3.rs:24:5
--> $DIR/super-traits-fail-3.rs:24:7
|
LL | x.a();
| ^^^^^
| ^
error: aborting due to 4 previous errors

View file

@ -26,13 +26,13 @@ error[E0277]: the trait bound `A: const Add42` is not satisfied
--> $DIR/tilde-const-and-const-params.rs:27:61
|
LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
| ^^^^^^^^^
| ^
error[E0277]: the trait bound `A: const Add42` is not satisfied
--> $DIR/tilde-const-and-const-params.rs:9:44
|
LL | fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
| ^^^^^^^^^
| ^
error: aborting due to 4 previous errors

View file

@ -2,13 +2,25 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied
--> $DIR/trait-where-clause-const.rs:21:5
|
LL | T::b();
| ^^^^^^
| ^
|
note: required by a bound in `Foo::b`
--> $DIR/trait-where-clause-const.rs:15:24
|
LL | fn b() where Self: ~const Bar;
| ^^^^^^ required by this bound in `Foo::b`
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
--> $DIR/trait-where-clause-const.rs:23:5
--> $DIR/trait-where-clause-const.rs:23:12
|
LL | T::c::<T>();
| ^^^^^^^^^^^
| ^
|
note: required by a bound in `Foo::c`
--> $DIR/trait-where-clause-const.rs:16:13
|
LL | fn c<T: ~const Bar>();
| ^^^^^^ required by this bound in `Foo::c`
error: aborting due to 2 previous errors

View file

@ -10,19 +10,19 @@ error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:29:37
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^
| ^
error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:33:50
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^
| ^
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:22:5
--> $DIR/unsatisfied-const-trait-bound.rs:22:15
|
LL | require::<Ty>();
| ^^^^^^^^^^^^^^^
| ^^
|
note: required by a bound in `require`
--> $DIR/unsatisfied-const-trait-bound.rs:8:15