Skip to content

Commit

Permalink
Auto merge of #132831 - workingjubilee:rollup-6fdif44, r=workingjubilee
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - #131258 (Stabilize s390x inline assembly)
 - #132801 (interpret: get_alloc_info: also return mutability)
 - #132823 (require const_impl_trait gate for all conditional and trait const calls)
 - #132824 (Update grammar in wasm-c-abi's compiler flag documentation)
 - #132825 (Exclude relnotes-tracking-issue from needs-triage)
 - #132828 (Additional tests to ensure let is rejected during parsing)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Nov 10, 2024
2 parents 7660aed + c19d56c commit 6689597
Show file tree
Hide file tree
Showing 38 changed files with 3,312 additions and 1,236 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::RiscV32
| asm::InlineAsmArch::RiscV64
| asm::InlineAsmArch::LoongArch64
| asm::InlineAsmArch::S390x
);
if !is_stable && !self.tcx.features().asm_experimental_arch() {
feature_err(
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ const_eval_closure_fndef_not_const =
function defined here, but it is not `const`
const_eval_closure_non_const =
cannot call non-const closure in {const_eval_const_context}s
const_eval_conditionally_const_call =
cannot call conditionally-const {$def_descr} `{$def_path_str}` in {const_eval_const_context}s
const_eval_consider_dereferencing =
consider dereferencing here
Expand Down
89 changes: 30 additions & 59 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_mir_dataflow::Analysis;
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
Expand Down Expand Up @@ -361,31 +361,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
!is_transient
}

/// Returns whether there are const-conditions.
fn revalidate_conditional_constness(
&mut self,
callee: DefId,
callee_args: ty::GenericArgsRef<'tcx>,
call_source: CallSource,
call_span: Span,
) {
) -> bool {
let tcx = self.tcx;
if !tcx.is_conditionally_const(callee) {
return;
return false;
}

let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
// If there are any const conditions on this fn and `const_trait_impl`
// is not enabled, simply bail. We shouldn't be able to call conditionally
// const functions on stable.
if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
self.check_op(ops::FnCallNonConst {
callee,
args: callee_args,
span: call_span,
call_source,
feature: Some(sym::const_trait_impl),
});
return;
if const_conditions.is_empty() {
return false;
}

let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
Expand Down Expand Up @@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
tcx.dcx()
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
}

true
}
}

Expand Down Expand Up @@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
_ => unreachable!(),
};

let ConstCx { tcx, body, param_env, .. } = *self.ccx;
let ConstCx { tcx, body, .. } = *self.ccx;

let fn_ty = func.ty(body, tcx);

let (mut callee, mut fn_args) = match *fn_ty.kind() {
let (callee, fn_args) = match *fn_ty.kind() {
ty::FnDef(def_id, fn_args) => (def_id, fn_args),

ty::FnPtr(..) => {
Expand All @@ -645,57 +637,38 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
};

self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
let has_const_conditions =
self.revalidate_conditional_constness(callee, fn_args, *fn_span);

let mut is_trait = false;
// Attempting to call a trait method?
if let Some(trait_did) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
// We can't determine the actual callee here, so we have to do different checks
// than usual.

trace!("attempting to call a trait method");
let trait_is_const = tcx.is_const_trait(trait_did);
// trait method calls are only permitted when `effects` is enabled.
// typeck ensures the conditions for calling a const trait method are met,
// so we only error if the trait isn't const. We try to resolve the trait
// into the concrete method, and uses that for const stability checks.
// FIXME(const_trait_impl) we might consider moving const stability checks
// to typeck as well.
if tcx.features().const_trait_impl() && trait_is_const {
// This skips the check below that ensures we only call `const fn`.
is_trait = true;

if let Ok(Some(instance)) =
Instance::try_resolve(tcx, param_env, callee, fn_args)
&& let InstanceKind::Item(def) = instance.def
{
// Resolve a trait method call to its concrete implementation, which may be in a
// `const` trait impl. This is only used for the const stability check below, since
// we want to look at the concrete impl's stability.
fn_args = instance.args;
callee = def;
}

if trait_is_const {
// Trait calls are always conditionally-const.
self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
// FIXME(const_trait_impl): do a more fine-grained check whether this
// particular trait can be const-stably called.
} else {
// if the trait is const but the user has not enabled the feature(s),
// suggest them.
let feature = if trait_is_const {
Some(if tcx.features().const_trait_impl() {
sym::effects
} else {
sym::const_trait_impl
})
} else {
None
};
// Not even a const trait.
self.check_op(ops::FnCallNonConst {
callee,
args: fn_args,
span: *fn_span,
call_source,
feature,
});
// If we allowed this, we're in miri-unleashed mode, so we might
// as well skip the remaining checks.
return;
}
// That's all we can check here.
return;
}

// Even if we know the callee, ensure we can use conditionally-const calls.
if has_const_conditions {
self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
}

// At this point, we are calling a function, `callee`, whose `DefId` is known...
Expand Down Expand Up @@ -783,14 +756,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}

// Trait functions are not `const fn` so we have to skip them here.
if !tcx.is_const_fn(callee) && !is_trait {
if !tcx.is_const_fn(callee) {
self.check_op(ops::FnCallNonConst {
callee,
args: fn_args,
span: *fn_span,
call_source,
feature: None,
});
// If we allowed this, we're in miri-unleashed mode, so we might
// as well skip the remaining checks.
Expand Down
53 changes: 34 additions & 19 deletions compiler/rustc_const_eval/src/check_consts/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,52 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
}
}

/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
#[derive(Debug)]
pub(crate) struct ConditionallyConstCall<'tcx> {
pub callee: DefId,
pub args: GenericArgsRef<'tcx>,
}

impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
// We use the `const_trait_impl` gate for all conditionally-const calls.
Status::Unstable {
gate: sym::const_trait_impl,
safe_to_expose_on_stable: false,
// We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
is_function_call: false,
}
}

fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
ccx.tcx.sess.create_feature_err(
errors::ConditionallyConstCall {
span,
def_path_str: ccx.tcx.def_path_str_with_args(self.callee, self.args),
def_descr: ccx.tcx.def_descr(self.callee),
kind: ccx.const_kind(),
},
sym::const_trait_impl,
)
}
}

/// A function call where the callee is not marked as `const`.
#[derive(Debug, Clone, Copy)]
pub(crate) struct FnCallNonConst<'tcx> {
pub callee: DefId,
pub args: GenericArgsRef<'tcx>,
pub span: Span,
pub call_source: CallSource,
pub feature: Option<Symbol>,
}

impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
let FnCallNonConst { callee, args, span, call_source, feature } = *self;
let FnCallNonConst { callee, args, span, call_source } = *self;
let ConstCx { tcx, param_env, .. } = *ccx;
let caller = ccx.def_id();

Expand Down Expand Up @@ -285,14 +315,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx.const_kind(),
));

if let Some(feature) = feature {
ccx.tcx.disabled_nightly_features(
&mut err,
Some(ccx.tcx.local_def_id_to_hir_id(caller)),
[(String::new(), feature)],
);
}

if let ConstContext::Static(_) = ccx.const_kind() {
err.note(fluent_generated::const_eval_lazy_lock);
}
Expand Down Expand Up @@ -398,15 +420,8 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {

fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
if let hir::CoroutineKind::Desugared(
hir::CoroutineDesugaring::Async,
hir::CoroutineSource::Block,
) = self.0
{
ccx.tcx.sess.create_feature_err(
errors::UnallowedOpInConstContext { span, msg },
sym::const_async_blocks,
)
if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
} else {
ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
}
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,9 @@ fn report_validation_error<'tcx>(
backtrace.print_backtrace();

let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
let (size, align, _) = ecx.get_alloc_info(alloc_id);
let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes };
let info = ecx.get_alloc_info(alloc_id);
let raw_bytes =
errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };

crate::const_eval::report(
*ecx.tcx,
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,16 @@ pub(crate) struct NonConstFmtMacroCall {
pub kind: ConstContext,
}

#[derive(Diagnostic)]
#[diag(const_eval_conditionally_const_call)]
pub(crate) struct ConditionallyConstCall {
#[primary_span]
pub span: Span,
pub def_path_str: String,
pub def_descr: &'static str,
pub kind: ConstContext,
}

#[derive(Diagnostic)]
#[diag(const_eval_non_const_fn_call, code = E0015)]
pub(crate) struct NonConstFnCall {
Expand Down
Loading

0 comments on commit 6689597

Please sign in to comment.