Skip to content

Commit a6e516e

Browse files
JustusAdamkarkhazadpaco-aws
authored
Throw a graceful error when type checking for ctpop fails (rust-lang#2504)
Co-authored-by: Kareem Khazem <karkhaz@amazon.com> Co-authored-by: Adrian Palacios <73246657+adpaco-aws@users.noreply.github.com>
1 parent bf603f0 commit a6e516e

File tree

6 files changed

+63
-5
lines changed

6 files changed

+63
-5
lines changed

kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,20 @@ impl<'tcx> GotocCtx<'tcx> {
120120
}
121121
}
122122

123-
/// c.f. `rustc_codegen_llvm::intrinsic` `impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx>`
124-
/// `fn codegen_intrinsic_call`
125-
/// c.f. <https://doc.rust-lang.org/std/intrinsics/index.html>
123+
/// c.f. `rustc_codegen_llvm::intrinsic` `impl IntrinsicCallMethods<'tcx>
124+
/// for Builder<'a, 'll, 'tcx>` `fn codegen_intrinsic_call` c.f.
125+
/// <https://doc.rust-lang.org/std/intrinsics/index.html>
126+
///
127+
/// ### A note on type checking
128+
///
129+
/// The backend/codegen generally assumes that at this point arguments have
130+
/// been type checked and that the given intrinsic is safe to call with the
131+
/// provided arguments. However in rare cases the intrinsics type signature
132+
/// is too permissive or has to be liberal because the types are enforced by
133+
/// the specific code gen/backend. In such cases we handle the type checking
134+
/// here. The type constraints enforced here must be at least as strict as
135+
/// the assertions made in in the builder functions in
136+
/// [`Expr`].
126137
fn codegen_intrinsic(
127138
&mut self,
128139
instance: Instance<'tcx>,
@@ -445,7 +456,7 @@ impl<'tcx> GotocCtx<'tcx> {
445456
"cosf64" => codegen_simple_intrinsic!(Cos),
446457
"ctlz" => codegen_count_intrinsic!(ctlz, true),
447458
"ctlz_nonzero" => codegen_count_intrinsic!(ctlz, false),
448-
"ctpop" => self.codegen_expr_to_place(p, fargs.remove(0).popcount()),
459+
"ctpop" => self.codegen_ctpop(*p, span, fargs.remove(0), farg_types[0]),
449460
"cttz" => codegen_count_intrinsic!(cttz, true),
450461
"cttz_nonzero" => codegen_count_intrinsic!(cttz, false),
451462
"discriminant_value" => {
@@ -650,6 +661,48 @@ impl<'tcx> GotocCtx<'tcx> {
650661
}
651662
}
652663

664+
/// Perform type checking and code generation for the `ctpop` rust intrinsic.
665+
fn codegen_ctpop(
666+
&mut self,
667+
target_place: Place<'tcx>,
668+
span: Option<Span>,
669+
arg: Expr,
670+
arg_rust_ty: Ty<'tcx>,
671+
) -> Stmt {
672+
if !arg.typ().is_integer() {
673+
self.intrinsics_typecheck_fail(span, "ctpop", "integer type", arg_rust_ty)
674+
} else {
675+
self.codegen_expr_to_place(&target_place, arg.popcount())
676+
}
677+
}
678+
679+
/// Report that a delayed type check on an intrinsic failed.
680+
///
681+
/// The idea is to blame one of the arguments on the failed type check and
682+
/// report the type that was found for that argument in `actual`. The
683+
/// `expected` type for that argument can be very permissive (e.g. "some
684+
/// integer type") and as a result it allows a permissive string as
685+
/// description.
686+
///
687+
/// Calling this function will abort the compilation though that is not
688+
/// obvious by the type.
689+
fn intrinsics_typecheck_fail(
690+
&self,
691+
span: Option<Span>,
692+
name: &str,
693+
expected: &str,
694+
actual: Ty,
695+
) -> ! {
696+
self.tcx.sess.span_err(
697+
span.into_iter().collect::<Vec<_>>(),
698+
format!(
699+
"Type check failed for intrinsic `{name}`: Expected {expected}, found {actual}"
700+
),
701+
);
702+
self.tcx.sess.abort_if_errors();
703+
unreachable!("Rustc should have aborted already")
704+
}
705+
653706
// Fast math intrinsics for floating point operations like `fadd_fast`
654707
// assume that their inputs are finite:
655708
// https://doc.rust-lang.org/std/intrinsics/fn.fadd_fast.html
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
error: Type check failed for intrinsic `ctpop`: Expected integer type, found ()
2+
|
3+
12 | let n = ctpop(());
4+
| ^^^^^^^^^
5+
6+
error: aborting due to previous error

tests/expected/intrinsics/sub_with_workflow_ice_fixme/expected

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)