Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5b8f281
new branch, fresh git history.
TirushOne Sep 1, 2026
533e60d
Minor cleanup in rustc_hir_analysis::collect
fmease Aug 30, 2026
29d38e4
Support type-relative assoc item paths in generic param defaults & co…
fmease Aug 30, 2026
5941c0b
properly ignore the current goal's usages
sjwang05 Oct 8, 2026
f21a12a
In the `BestObligation` prooftree visitor, we now only skip any candi…
LorrensP-2158466 Sep 7, 2026
3940850
show span-only suggestions when source is unavailable in ui tests
xizheyin Oct 9, 2026
9bc17fd
Don't rewrite alias outlives in smaller universes
BoxyUwU Oct 7, 2026
7d43809
Produce less general higher ranked alias constraints
BoxyUwU Oct 7, 2026
07d67c6
Better debug impls for abby stuff
BoxyUwU Oct 7, 2026
f4b0976
Fix for const generic parameter checking
Jamesbarford Oct 9, 2026
901cebd
Update tests and create new tests for const generic parameter checking
Jamesbarford Oct 9, 2026
e3941d6
const-eval: ICE when we hit a non-const fn
RalfJung Oct 8, 2026
02dbf08
Allow testing cg-gcc on any target
Kobzol Oct 9, 2026
307733f
Rollup merge of #144585 - xizheyin:show-std-source, r=estebank
JonathanBrouwer Oct 9, 2026
97d1dd0
Rollup merge of #161998 - fmease:tyrel-in-gen-param-cx, r=jackh726
JonathanBrouwer Oct 9, 2026
2e5a959
Rollup merge of #162106 - TirushOne:addr-mutability-suggestions, r=ja…
JonathanBrouwer Oct 9, 2026
7e175cb
Rollup merge of #163938 - BoxyUwU:abby_more_correct_alias_rewriting, …
JonathanBrouwer Oct 9, 2026
18be71f
Rollup merge of #163939 - BoxyUwU:abby_slight_debug_impl_improvements…
JonathanBrouwer Oct 9, 2026
c8ddead
Rollup merge of #164042 - Kobzol:cg-gcc-target, r=GuillaumeGomez
JonathanBrouwer Oct 9, 2026
82f381f
Rollup merge of #162443 - LorrensP-2158466:fix-best-obligation-visito…
JonathanBrouwer Oct 9, 2026
c7114a5
Rollup merge of #162908 - Jamesbarford:fix/const-generic-bug, r=khyperia
JonathanBrouwer Oct 9, 2026
2301061
Rollup merge of #163972 - RalfJung:non-const-eval, r=oli-obk
JonathanBrouwer Oct 9, 2026
cb318fd
Rollup merge of #164008 - sjwang05:ignore-usages, r=lcnr
JonathanBrouwer Oct 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,16 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
// all. That said, we have to allow calling functions inside a `const trait`. These
// *are* const-checked!
if !ecx.tcx.is_const_fn(def) || find_attr!(ecx.tcx, def, RustcDoNotConstCheck) {
// We certainly do *not* want to actually call the fn
// though, so be sure we return here.
throw_unsup_format!("calling non-const function `{}`", instance)
// We certainly do *not* want to actually call this fn. const-checking should have
// prevented this, but this can be reached with unleashed-miri, so make testing
// simpler by avoiding ICEs there. (Technically this can still ICE if miri-unleash
// was set in a dependency rather than the current crate. That's okay, it's an
// internal unstable feature.)
if ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
throw_unsup_format!("calling non-const function `{}`", instance)
} else {
span_bug!(ecx.cur_span(), "calling non-const function `{}`", instance)
}
}
}

Expand Down
65 changes: 65 additions & 0 deletions compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct AnnotateSnippetEmitter {
track_diagnostics: bool,
terminal_url: TerminalUrl,
theme: OutputTheme,
show_suggestions_with_unavailable_source: bool,
}

impl Debug for AnnotateSnippetEmitter {
Expand All @@ -60,6 +61,7 @@ impl Debug for AnnotateSnippetEmitter {
track_diagnostics,
terminal_url,
theme,
show_suggestions_with_unavailable_source,
} = self;

f.debug_struct("AnnotateSnippetEmitter")
Expand All @@ -73,6 +75,10 @@ impl Debug for AnnotateSnippetEmitter {
.field("track_diagnostics", track_diagnostics)
.field("terminal_url", terminal_url)
.field("theme", theme)
.field(
"show_suggestions_with_unavailable_source",
show_suggestions_with_unavailable_source,
)
.finish()
}
}
Expand Down Expand Up @@ -153,6 +159,7 @@ impl AnnotateSnippetEmitter {
track_diagnostics: false,
terminal_url: TerminalUrl::No,
theme: OutputTheme::Ascii,
show_suggestions_with_unavailable_source: false,
}
}

Expand Down Expand Up @@ -319,6 +326,12 @@ impl AnnotateSnippetEmitter {
SuggestionStyle::HideCodeInline
| SuggestionStyle::ShowCode
| SuggestionStyle::ShowAlways => {
// Get the original unavailable spans before `suggestion` is consumed.
let unavailable_source_span = if self.show_suggestions_with_unavailable_source {
self.suggestion_span_with_unavailable_source(sm, &suggestion)
} else {
None
};
let substitutions = suggestion
.substitutions
.into_iter()
Expand Down Expand Up @@ -368,6 +381,30 @@ impl AnnotateSnippetEmitter {
.collect::<Vec<_>>();

if substitutions.is_empty() {
if let Some(span) = unavailable_source_span {
let msg = format_diag_message(&suggestion.msg, args).to_string();
report.push(std::mem::replace(
&mut group,
Group::with_title(
annotate_snippets::Level::HELP.secondary_title(msg),
),
));

let file_ann = collect_annotations(args, &span, sm);
let level = annotate_snippets::Level::HELP;
for (file_idx, (file, annotations)) in file_ann.into_iter().enumerate()
{
group = self.unannotated_messages(
annotations,
&file.name,
sm,
file_idx,
&mut report,
group,
&level,
);
}
}
continue;
}
let mut msg = format_diag_message(&suggestion.msg, args).to_string();
Expand Down Expand Up @@ -652,6 +689,34 @@ impl AnnotateSnippetEmitter {
}
group
}

fn suggestion_span_with_unavailable_source(
&self,
sm: &Arc<SourceMap>,
suggestion: &CodeSuggestion,
) -> Option<MultiSpan> {
// These spans cannot be rendered as source patches because their source
// files are unavailable, but can still be shown as locations.
let spans = suggestion
.substitutions
.iter()
.flat_map(|subst| &subst.parts)
.filter_map(|part| {
if sm.is_valid_span(part.span).is_err() {
debug!("suggestion contains an invalid span: {:?}", part);
return None;
}
let lines = sm.span_to_lines(part.span).ok()?;
if sm.ensure_source_file_source_present(&lines.file) {
None
} else {
Some(part.span)
}
})
.collect::<Vec<_>>();

if spans.is_empty() { None } else { Some(MultiSpan::from_spans(spans)) }
}
}

fn emit_to_destination(
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_errors/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub struct JsonEmitter {
macro_backtrace: bool,
track_diagnostics: bool,
terminal_url: TerminalUrl,
show_suggestions_with_unavailable_source: bool,
}

impl JsonEmitter {
Expand All @@ -76,6 +77,7 @@ impl JsonEmitter {
macro_backtrace: false,
track_diagnostics: false,
terminal_url: TerminalUrl::No,
show_suggestions_with_unavailable_source: false,
}
}

Expand Down Expand Up @@ -361,6 +363,7 @@ impl Diagnostic {
.terminal_url(je.terminal_url)
.ui_testing(je.ui_testing)
.ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone())
.show_suggestions_with_unavailable_source(je.show_suggestions_with_unavailable_source)
.theme(if je.json_rendered.unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
.emit_diagnostic(diag);

Expand Down
135 changes: 104 additions & 31 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ fn check_method_is_structurally_compatible<'tcx>(
compare_self_type(tcx, impl_m, trait_m, impl_trait_ref, delay)?;
compare_number_of_generics(tcx, impl_m, trait_m, delay)?;
compare_generic_param_kinds(tcx, impl_m, trait_m, delay)?;
compare_const_generic_param_types(tcx, impl_m, trait_m, impl_trait_ref, delay)?;
compare_number_of_method_arguments(tcx, impl_m, trait_m, delay)?;
compare_synthetic_generics(tcx, impl_m, trait_m, delay)?;
check_region_bounds_on_impl_item(tcx, impl_m, trait_m, delay)?;
Expand Down Expand Up @@ -2034,31 +2035,8 @@ fn compare_synthetic_generics<'tcx>(
if let Some(reported) = error_found { Err(reported) } else { Ok(()) }
}

/// Checks that all parameters in the generics of a given assoc item in a trait impl have
/// the same kind as the respective generic parameter in the trait def.
///
/// For example all 4 errors in the following code are emitted here:
/// ```rust,ignore (pseudo-Rust)
/// trait Foo {
/// fn foo<const N: u8>();
/// type Bar<const N: u8>;
/// fn baz<const N: u32>();
/// type Blah<T>;
/// }
///
/// impl Foo for () {
/// fn foo<const N: u64>() {}
/// //~^ error
/// type Bar<const N: u64> = ();
/// //~^ error
/// fn baz<T>() {}
/// //~^ error
/// type Blah<const N: i64> = u32;
/// //~^ error
/// }
/// ```
///
/// This function does not handle lifetime parameters
/// Checks that corresponding generic parameters in a trait item and its impl
/// are both type parameters or both const parameters.
fn compare_generic_param_kinds<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: ty::AssocItem,
Expand All @@ -2081,11 +2059,6 @@ fn compare_generic_param_kinds<'tcx>(
{
use GenericParamDefKind::*;
if match (&param_impl.kind, &param_trait.kind) {
(Const { .. }, Const { .. })
if tcx.type_of(param_impl.def_id) != tcx.type_of(param_trait.def_id) =>
{
true
}
(Const { .. }, Type { .. }) | (Type { .. }, Const { .. }) => true,
// this is exhaustive so that anyone adding new generic param kinds knows
// to make sure this error is reported for them.
Expand All @@ -2104,7 +2077,7 @@ fn compare_generic_param_kinds<'tcx>(
"{} `{}` has an incompatible generic parameter for trait `{}`",
impl_item.descr(),
trait_item.name(),
&tcx.def_path_str(tcx.parent(trait_item.def_id))
tcx.def_path_str(tcx.parent(trait_item.def_id))
);

let make_param_message = |prefix: &str, param: &ty::GenericParamDef| match param.kind {
Expand Down Expand Up @@ -2138,6 +2111,98 @@ fn compare_generic_param_kinds<'tcx>(
Ok(())
}

/// Checks that corresponding const generic parameters in a trait item and its
/// impl have compatible types.
fn compare_const_generic_param_types<'tcx>(
tcx: TyCtxt<'tcx>,
impl_item: ty::AssocItem,
trait_item: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
assert_eq!(impl_item.tag(), trait_item.tag());
use GenericParamDefKind::*;

let const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| matches!(param.kind, Const { .. }))
};

// Map the trait item's generic parameters into the impl item's generic context.
let trait_to_impl_args = ty::GenericArgs::identity_for_item(tcx, impl_item.def_id).rebase_onto(
tcx,
impl_item.container_id(tcx),
impl_trait_ref.args,
);
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let param_env = tcx.param_env(impl_item.def_id);

let param_iter =
iter::zip(const_params_of(impl_item.def_id), const_params_of(trait_item.def_id));

for (param_impl, param_trait) in param_iter {
let param_impl_ty_span = tcx.ty_span(param_impl.def_id.expect_local());

let cause = ObligationCause::new(
param_impl_ty_span,
impl_item.def_id.expect_local(),
ObligationCauseCode::CompareImplItem {
impl_item_def_id: impl_item.def_id.expect_local(),
trait_item_def_id: trait_item.def_id,
kind: impl_item.kind,
},
);

let impl_ty =
ocx.normalize(&cause, param_env, tcx.type_of(param_impl.def_id).instantiate_identity());

let trait_ty = ocx.normalize(
&cause,
param_env,
tcx.type_of(param_trait.def_id).instantiate(tcx, trait_to_impl_args),
);

match ocx.eq(&cause, param_env, trait_ty, impl_ty) {
// Despite returning `Ok` all may not be well. As such, outside of this
// loop we invoke `ocx.evaluate_obligations_error_on_ambiguity()` to check
// for any other errors that may have occurred.
Ok(_) => {}
Err(terr) => {
let param_trait_ty_span =
param_trait.def_id.as_local().map(|def_id| tcx.ty_span(def_id));
let mut diag = struct_span_code_err!(
tcx.dcx(),
param_impl_ty_span,
E0053,
"{} `{}` has an incompatible type for const generic parameter",
trait_item.descr(),
trait_item.name(),
);
infcx.err_ctxt().note_type_err(
&mut diag,
&cause,
param_trait_ty_span.map(|span| (span, Cow::from("type in trait"), false)),
Some(param_env.and(infer::ValuePairs::Terms(ExpectedFound {
expected: trait_ty.into(),
found: impl_ty.into(),
}))),
terr,
false,
None,
);
let reported = diag.emit_err_unless_delay(delay);
return Err(reported);
}
}
}

if let TraitErrors::HasErrors(errors) = ocx.evaluate_obligations_error_on_ambiguity() {
Err(infcx.err_ctxt().report_fulfillment_errors(errors))
} else {
Ok(())
}
}

fn compare_impl_const<'tcx>(
tcx: TyCtxt<'tcx>,
impl_const_item: ty::AssocItem,
Expand All @@ -2147,6 +2212,13 @@ fn compare_impl_const<'tcx>(
compare_const_directness(tcx, impl_const_item, trait_const_item)?;
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
compare_const_generic_param_types(
tcx,
impl_const_item,
trait_const_item,
impl_trait_ref,
false,
)?;
check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?;
compare_const_clause_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
}
Expand Down Expand Up @@ -2325,6 +2397,7 @@ fn compare_impl_ty<'tcx>(
) -> Result<(), ErrorGuaranteed> {
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
compare_const_generic_param_types(tcx, impl_ty, trait_ty, impl_trait_ref, false)?;
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
compare_type_clause_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?;
check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)
Expand Down
25 changes: 12 additions & 13 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1760,28 +1760,27 @@ fn rendered_precise_capturing_args<'tcx>(

fn const_param_default<'tcx>(
tcx: TyCtxt<'tcx>,
local_def_id: LocalDefId,
param_def_id: LocalDefId,
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
let hir::Node::GenericParam(hir::GenericParam {
kind: hir::GenericParamKind::Const { default: Some(default_ct), .. },
kind: hir::GenericParamKind::Const { default: Some(ct), .. },
..
}) = tcx.hir_node_by_def_id(local_def_id)
}) = tcx.hir_node_by_def_id(param_def_id)
else {
span_bug!(
tcx.def_span(local_def_id),
"`const_param_default` expected a generic parameter with a constant"
tcx.def_span(param_def_id),
"const_param_default: expected a const parameter with a default value"
)
};

let icx = ItemCtxt::new(tcx, local_def_id);
// FIXME: Don't lower in the context of parent. Blocked on the removal of GCE. See comment in
// `type_of.rs` for details (Ctrl+F for `generics_of`).
let item_def_id = tcx.local_parent(param_def_id);
let icx = ItemCtxt::new(tcx, item_def_id);

let def_id = local_def_id.to_def_id();
let identity_args = ty::GenericArgs::identity_for_item(tcx, tcx.parent(def_id));

let ct = icx.lowerer().lower_const_arg(
default_ct,
tcx.type_of(def_id).instantiate(tcx, identity_args).skip_norm_wip(),
);
let ct = icx
.lowerer()
.lower_const_arg(ct, tcx.type_of(param_def_id).instantiate_identity().skip_norm_wip());
ty::EarlyBinder::bind(tcx, ct)
}

Expand Down
Loading
Loading