Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable calling all const traits in stable const #132786

Conversation

compiler-errors
Copy link
Member

r? @RalfJung

I hesitate to make this a separate NonConstOp since its error reporting would be basically totally identical to the existing FnCallNonConst. Instead, if a trait is const, we set the status to Status::Unstable; otherwise it remains Status::Forbidden. Am I missing something about this not being sufficient?

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 8, 2024
@rustbot
Copy link
Collaborator

rustbot commented Nov 8, 2024

Some changes occurred to the CTFE machinery

cc @rust-lang/wg-const-eval

@RalfJung
Copy link
Member

RalfJung commented Nov 8, 2024

I hesitate to make this a separate NonConstOp since its error reporting would be basically totally identical to the existing FnCallNonConst

How that? It's checking a quite different thing, so the diagnostics should be rather different. So IMO it makes a lot more sense for this to be a new Op.

@compiler-errors
Copy link
Member Author

so the diagnostics should be rather different.

I'm not certain what about the diagnostic would differ?

Out of the matrix of the feature gate being enabled (yes/no) and the trait being const (yes/no), in all cases we're basically just saying that it's not possible to call a trait method in a const context. And most of what goes into FnCallNonConst is describing what kind of thing is being called. While there's some machinery about missing ~const bounds that could be cut out, I basically don't want to just replicate this whole match statement twice:

let mut err = match call_kind {
CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
macro_rules! error {
($err:ident) => {
tcx.dcx().create_err(errors::$err {
span,
ty: self_ty,
kind: ccx.const_kind(),
})
};
}
let mut err = match kind {
CallDesugaringKind::ForLoopIntoIter => {
error!(NonConstForLoopIntoIter)
}
CallDesugaringKind::QuestionBranch => {
error!(NonConstQuestionBranch)
}
CallDesugaringKind::QuestionFromResidual => {
error!(NonConstQuestionFromResidual)
}
CallDesugaringKind::TryBlockFromOutput => {
error!(NonConstTryBlockFromOutput)
}
CallDesugaringKind::Await => {
error!(NonConstAwait)
}
};
diag_trait(&mut err, self_ty, kind.trait_def_id(tcx));
err
}
CallKind::FnCall { fn_trait_id, self_ty } => {
let note = match self_ty.kind() {
FnDef(def_id, ..) => {
let span = tcx.def_span(*def_id);
if ccx.tcx.is_const_fn(*def_id) {
span_bug!(span, "calling const FnDef errored when it shouldn't");
}
Some(errors::NonConstClosureNote::FnDef { span })
}
FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr),
Closure(..) => Some(errors::NonConstClosureNote::Closure),
_ => None,
};
let mut err = tcx.dcx().create_err(errors::NonConstClosure {
span,
kind: ccx.const_kind(),
note,
});
diag_trait(&mut err, self_ty, fn_trait_id);
err
}
CallKind::Operator { trait_id, self_ty, .. } => {
let mut err = if let CallSource::MatchCmp = call_source {
tcx.dcx().create_err(errors::NonConstMatchEq {
span,
kind: ccx.const_kind(),
ty: self_ty,
})
} else {
let mut sugg = None;
if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) {
match (args[0].unpack(), args[1].unpack()) {
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
if self_ty == rhs_ty
&& self_ty.is_ref()
&& self_ty.peel_refs().is_primitive() =>
{
let mut num_refs = 0;
let mut tmp_ty = self_ty;
while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
num_refs += 1;
tmp_ty = *inner_ty;
}
let deref = "*".repeat(num_refs);
if let Ok(call_str) =
ccx.tcx.sess.source_map().span_to_snippet(span)
{
if let Some(eq_idx) = call_str.find("==") {
if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
.find(|c: char| !c.is_whitespace())
{
let rhs_pos = span.lo()
+ BytePos::from_usize(eq_idx + 2 + rhs_idx);
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
sugg = Some(errors::ConsiderDereferencing {
deref,
span: span.shrink_to_lo(),
rhs_span,
});
}
}
}
}
_ => {}
}
}
tcx.dcx().create_err(errors::NonConstOperator {
span,
kind: ccx.const_kind(),
sugg,
})
};
diag_trait(&mut err, self_ty, trait_id);
err
}
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
// Check first whether the source is accessible (issue #87060)
let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
Some(deref_target)
} else {
None
};
let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
span,
ty: self_ty,
kind: ccx.const_kind(),
target_ty: deref_target_ty,
deref_target: target,
});
diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
err
}
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() })
}
_ => ccx.dcx().create_err(errors::NonConstFnCall {
span,
def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
kind: ccx.const_kind(),
}),
};

@RalfJung
Copy link
Member

RalfJung commented Nov 9, 2024

FnCallNonConst is for non-const functions. It just makes logically no sense to use it for "the function is const but there's a lang feature involved that is not enabled".

The entire idea of these "ops" is to have one Op per thing-that-needs-to-be-enabled. With const trait calls, there are two things that need to be enabled:

  • the ability to do trait calls at all
  • the specific feature gate for the trait being called (not sure if that's already implemented, we talked about having a per-trait control here eventually -- but that is not required for the first iteration)

I can see no reason at all for why one would want to merge these into a single check. That's just confusing.

args: fn_args,
span: *fn_span,
call_source,
feature: tcx.is_const_trait(trait_did).then_some(sym::const_trait_impl),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing, it conflates two entirely orthogonal checks:

  • is this trait const-callable
  • are we allowed to do const trait calls

Why is the first check even here, didn't revalidate_conditional_constness already check that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

revalidate_conditional_constness just checks that if the item is conditionally const then the trait bounds ~const trait bounds hold. For example, if a free function item is not conditionally const, then it will have no ~const trait bounds, so revalidate_conditional_constness is not enforcing anything in that case.

Comment on lines +655 to +656
// FIXME: apply more fine-grained per-trait const stability checks
// (see <https://github.com/rust-lang/project-const-traits/issues/5>).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// FIXME: apply more fine-grained per-trait const stability checks
// (see <https://github.com/rust-lang/project-const-traits/issues/5>).

This is repeated below, no need to have it twice.

@RalfJung
Copy link
Member

RalfJung commented Nov 9, 2024

FWIW this will conflict with #132541

@@ -32,43 +35,28 @@ fn non_const_context() {
#[unstable(feature = "none", issue = "none")]
const fn const_context() {
Unstable::func();
//[unstable]~^ ERROR cannot use `#[feature(unstable)]`
//[stable]~^^ ERROR not yet stable as a const fn
Copy link
Member

@RalfJung RalfJung Nov 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something has gone very wrong here. This should complain about the missing feature gate -- const_trait_impl can't be used here since the function does not have #[rustc_const_unstable]. That's the entire point!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you're misinterpreting what I did to this file lol. I marked the whole thing as a known-bug, which requires that the test have no error annotation, because this whole test is basically useless if we have no staged apis for const traits.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a test to ensure that we can't call trait functions on stable. Why shouldn't that be this file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this test does a lot more than just ensure we can't call trait functions on stable. If we want a test to do that, then it can be like... 10 lines. It's got like... several revisions, an aux-build dep that is also broken due to these changes, etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need an aux build to properly check the cross-crate part of this. And the revisions distinguish whether the trait callee is stable or not, which the old check was sensitive to when it could resolve the callee... I guess for now we don't need the revisions; once we have the ability to do a per-trait decision of "can this be const-called on stable", that will be relevant again.

@RalfJung
Copy link
Member

RalfJung commented Nov 9, 2024

In fact I think the feature field should be removed from FnCallNonConst. That NonConstOp is meant for functions that genuinely are not const, and there can't be a feature gate for calling those.

@compiler-errors compiler-errors deleted the all-const-traits-are-unstable branch November 9, 2024 21:54
workingjubilee added a commit to workingjubilee/rustc that referenced this pull request Nov 10, 2024
…r=fee1-dead,compiler-errors

require const_impl_trait gate for all conditional and trait const calls

Alternative to rust-lang#132786.

`@compiler-errors`  this is basically what I meant with my proposals. I found it's easier to express this in code than English. ;)

r? `@compiler-errors`
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Nov 10, 2024
Rollup merge of rust-lang#132823 - RalfJung:conditional-const-calls, r=fee1-dead,compiler-errors

require const_impl_trait gate for all conditional and trait const calls

Alternative to rust-lang#132786.

`@compiler-errors`  this is basically what I meant with my proposals. I found it's easier to express this in code than English. ;)

r? `@compiler-errors`
RalfJung pushed a commit to RalfJung/miri that referenced this pull request Nov 10, 2024
…ad,compiler-errors

require const_impl_trait gate for all conditional and trait const calls

Alternative to rust-lang/rust#132786.

`@compiler-errors`  this is basically what I meant with my proposals. I found it's easier to express this in code than English. ;)

r? `@compiler-errors`
mati865 pushed a commit to mati865/rust that referenced this pull request Nov 12, 2024
…r=fee1-dead,compiler-errors

require const_impl_trait gate for all conditional and trait const calls

Alternative to rust-lang#132786.

`@compiler-errors`  this is basically what I meant with my proposals. I found it's easier to express this in code than English. ;)

r? `@compiler-errors`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants