Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4339,6 +4339,7 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_hashes",
"rustc_hir",
"rustc_index",
"rustc_infer",
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match const_context {
Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => {}
Some(hir::ConstContext::ConstFn) | None => {
self.dcx().span_err(span, "comptime fns can only be called at compile time");
self.dcx().emit_err(diagnostics::ComptimeFnCalledOutsideConstContext {
span,
const_block: diagnostics::WrapConstBlock {
left: span.shrink_to_lo(),
right: span.shrink_to_hi(),
},
});
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions compiler/rustc_hir_typeck/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1349,3 +1349,24 @@ impl ExprParenthesesNeeded {
#[derive(Diagnostic)]
#[diag("`#[panic_handler]` functions can't be `unsafe`")]
pub(crate) struct UnsafePanicHandlers;

#[derive(Diagnostic)]
#[diag("comptime functions can only be called at compile time")]
pub(crate) struct ComptimeFnCalledOutsideConstContext {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub const_block: WrapConstBlock,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
"wrap the call in a const block to force compile time evaluation",
applicability = "maybe-incorrect"
)]
pub(crate) struct WrapConstBlock {
#[suggestion_part(code = "const {{ ")]
pub left: Span,
#[suggestion_part(code = " }}")]
pub right: Span,
}
1 change: 1 addition & 0 deletions compiler/rustc_lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_hashes = { path = "../rustc_hashes" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ late_lint_methods!(
ImplTraitOvercaptures: ImplTraitOvercaptures,
ImplicitAutorefs: ImplicitAutorefs,
ImplicitProvenanceCasts: ImplicitProvenanceCasts,
ImproperCTypesLint: ImproperCTypesLint,
ImproperCTypesLint: ImproperCTypesLint::default(),
ImproperGpuKernelLint: ImproperGpuKernelLint,
InteriorMutableConsts: InteriorMutableConsts,
InternalEqTraitMethodImpls: InternalEqTraitMethodImpls,
Expand Down
73 changes: 60 additions & 13 deletions compiler/rustc_lint/src/types/improper_ctypes.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use std::cell::RefCell;
use std::iter;
use std::ops::ControlFlow;

use bitflags::bitflags;
use rustc_abi::VariantIdx;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{DiagMessage, msg};
use rustc_hashes::Hash128;
use rustc_hir::def::CtorKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, AmbigArg};
use rustc_lint_defs::{declare_lint, declare_lint_pass};
use rustc_lint_defs::{declare_lint, impl_lint_pass};
use rustc_middle::ty::{
self, Adt, AdtDef, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, Unnormalized,
Expand Down Expand Up @@ -131,7 +133,48 @@ declare_lint! {
"Structs do not follow the power alignment rule under repr(C)"
}

declare_lint_pass!(ImproperCTypesLint => [
/// Remembers types we already checked and found FFI-safe, so we don't check the
/// same type again every time it shows up in another function.
/// We only remember "safe" types, never "unsafe" ones. That way we never need to
/// keep the actual type around, just a fingerprint of it.
#[derive(Default)]
pub(crate) struct ImproperCTypesLint {
/// A fingerprint of the type, not the type itself. Uses a big 128-bit
/// fingerprint (not a smaller 64-bit one) so two different types can't
/// accidentally get treated as the same one.
known_safe: RefCell<FxHashSet<(Hash128, u8)>>,
}

impl<'tcx> ImproperCTypesLint {
fn cache_key(cx: &LateContext<'tcx>, ty: Ty<'tcx>, flags: RootUseFlags) -> (Hash128, u8) {
(cx.tcx.type_id_hash(ty), flags.bits())
}

fn check_ffi_type(
&self,
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
state: VisitorState,
span: Span,
mode: CItemKind,
check: impl FnOnce() -> FfiResult<'tcx>,
) {
let key = Self::cache_key(cx, ty, state.root_use_flags);
if self.known_safe.borrow().contains(&key) {
return;
}

let ffi_res = check();

if matches!(ffi_res, FfiResult::FfiSafe) {
self.known_safe.borrow_mut().insert(key);
}

self.process_ffi_result(cx, span, ffi_res, mode);
}
}

impl_lint_pass!(ImproperCTypesLint => [
IMPROPER_CTYPES,
IMPROPER_CTYPES_DEFINITIONS,
USES_POWER_ALIGNMENT
Expand Down Expand Up @@ -1102,9 +1145,11 @@ impl<'tcx> ImproperCTypesLint {

fn check_foreign_static(&mut self, cx: &LateContext<'tcx>, id: hir::OwnerId, span: Span) {
let ty = cx.tcx.type_of(id).instantiate_identity();
let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
let ffi_res = visitor.check_type(VisitorState::static_entry_point(), ty);
self.process_ffi_result(cx, span, ffi_res, CItemKind::Declaration);
let state = VisitorState::static_entry_point();
self.check_ffi_type(cx, ty.skip_norm_wip(), state, span, CItemKind::Declaration, || {
let mut visitor = ImproperCTypesVisitor::new(cx, ty, CItemKind::Declaration);
visitor.check_type(state, ty)
});
}

/// Check if a function's argument types and result type are "ffi-safe".
Expand All @@ -1119,19 +1164,21 @@ impl<'tcx> ImproperCTypesLint {
let sig = cx.tcx.instantiate_bound_regions_with_erased(sig);

for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
let input_ty = Unnormalized::new_wip(*input_ty);
let state = VisitorState::fn_entry_point(fn_mode, FnPos::Arg);
let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode);
let ffi_res = visitor.check_type(state, input_ty);
self.process_ffi_result(cx, input_hir.span, ffi_res, fn_mode);
self.check_ffi_type(cx, *input_ty, state, input_hir.span, fn_mode, || {
let input_ty = Unnormalized::new_wip(*input_ty);
let mut visitor = ImproperCTypesVisitor::new(cx, input_ty, fn_mode);
visitor.check_type(state, input_ty)
});
}

if let hir::FnRetTy::Return(ret_hir) = decl.output {
let output_ty = Unnormalized::new_wip(sig.output());
let state = VisitorState::fn_entry_point(fn_mode, FnPos::Ret);
let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode);
let ffi_res = visitor.check_type(state, output_ty);
self.process_ffi_result(cx, ret_hir.span, ffi_res, fn_mode);
self.check_ffi_type(cx, sig.output(), state, ret_hir.span, fn_mode, || {
let output_ty = Unnormalized::new_wip(sig.output());
let mut visitor = ImproperCTypesVisitor::new(cx, output_ty, fn_mode);
visitor.check_type(state, output_ty)
});
}
}

Expand Down
8 changes: 4 additions & 4 deletions library/std/src/sys/thread_local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

cfg_select! {
any(
all(target_family = "wasm", not(target_feature = "atomics"), not(target_env = "p3")),
all(target_family = "wasm", not(target_feature = "atomics"), not(target_os = "wasi")),
target_os = "uefi",
target_os = "zkvm",
target_os = "trusty",
Expand Down Expand Up @@ -66,7 +66,7 @@ cfg_select! {
/// single callback that runs all of the destructors in the list.
#[cfg(all(
target_thread_local,
not(all(target_family = "wasm", not(target_feature = "atomics"), not(target_env = "p3")))
not(all(target_family = "wasm", not(target_feature = "atomics"), not(target_os = "wasi")))
))]
pub(crate) mod destructors {
cfg_select! {
Expand Down Expand Up @@ -106,7 +106,7 @@ pub(crate) mod guard {
pub(crate) use windows::enable;
}
any(
all(target_family = "wasm", not(target_env = "p3")),
all(target_family = "wasm", not(target_os = "wasi")),
target_os = "uefi",
target_os = "zkvm",
target_os = "trusty",
Expand Down Expand Up @@ -154,7 +154,7 @@ pub(crate) mod key {
all(not(target_vendor = "apple"), not(target_family = "wasm"), target_family = "unix"),
all(not(target_thread_local), target_vendor = "apple"),
target_os = "teeos",
all(target_os = "wasi", target_env = "p3"),
target_os = "wasi",
) => {
mod racy;
mod unix;
Expand Down
4 changes: 2 additions & 2 deletions src/doc/rustc/src/platform-support/wasm32-wasip1.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ be used instead.
## Building the target in rustc

To build this target first acquire a copy of [`wasi-sdk`]. At this time version
33 is the minimum needed.
34 is the minimum needed.

Next configure the `WASI_SDK_PATH` environment variable to point to where this
is installed. For example:

```text
export WASI_SDK_PATH=/path/to/wasi-sdk-33.0
export WASI_SDK_PATH=/path/to/wasi-sdk-34.0
```

Next be sure to enable LLD when building Rust from source as LLVM's `wasm-ld`
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/comptime/comptime_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ const _: () = {

fn main() {
Bar.boo();
//~^ ERROR: comptime fns can only be called at compile time
//~^ ERROR: comptime functions can only be called at compile time
}
7 changes: 6 additions & 1 deletion tests/ui/comptime/comptime_method.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error: comptime fns can only be called at compile time
error: comptime functions can only be called at compile time
--> $DIR/comptime_method.rs:15:5
|
LL | Bar.boo();
| ^^^^^^^^^
|
help: wrap the call in a const block to force compile time evaluation
|
LL | const { Bar.boo() };
| +++++++ +

error: aborting due to 1 previous error

4 changes: 2 additions & 2 deletions tests/ui/comptime/not_callable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ fn main() {
// Ok
const { foo() };
// Not Ok
foo(); //~ ERROR: comptime fns can only be called at compile time
foo(); //~ ERROR: comptime functions can only be called at compile time
}

const fn bar() {
// Not Ok
foo(); //~ ERROR: comptime fns can only be called at compile time
foo(); //~ ERROR: comptime functions can only be called at compile time
}

#[rustc_comptime]
Expand Down
14 changes: 12 additions & 2 deletions tests/ui/comptime/not_callable.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
error: comptime fns can only be called at compile time
error: comptime functions can only be called at compile time
--> $DIR/not_callable.rs:10:5
|
LL | foo();
| ^^^^^
|
help: wrap the call in a const block to force compile time evaluation
|
LL | const { foo() };
| +++++++ +

error: comptime fns can only be called at compile time
error: comptime functions can only be called at compile time
--> $DIR/not_callable.rs:15:5
|
LL | foo();
| ^^^^^
|
help: wrap the call in a const block to force compile time evaluation
|
LL | const { foo() };
| +++++++ +

error: aborting due to 2 previous errors

2 changes: 1 addition & 1 deletion tests/ui/reflection/reflection_methods_in_runtime_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ trait Trait {}
fn main() {
// Test the (lack of) usability of comptime fns in runtime code.
std::any::TypeId::of::<[u8; usize::MAX]>().trait_info_of::<dyn Trait>();
//~^ ERROR: comptime fns can only be called at compile time
//~^ ERROR: comptime functions can only be called at compile time
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
error: comptime fns can only be called at compile time
error: comptime functions can only be called at compile time
--> $DIR/reflection_methods_in_runtime_code.rs:7:5
|
LL | std::any::TypeId::of::<[u8; usize::MAX]>().trait_info_of::<dyn Trait>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: wrap the call in a const block to force compile time evaluation
|
LL | const { std::any::TypeId::of::<[u8; usize::MAX]>().trait_info_of::<dyn Trait>() };
| +++++++ +

error: aborting due to 1 previous error

Loading