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

Rollup of 9 pull requests #120309

Merged
merged 22 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bed0c9d
[style 2024] Combine all last arg delimited exprs
pitaj Aug 12, 2023
b152de2
coverage: Discard code regions that might cause fatal errors in `llvm…
Zalathar Jan 5, 2024
41dcba8
coverage: Don't instrument `#[automatically_derived]` functions
Zalathar Jan 21, 2024
21e5bea
Use debug_assert instead of expanded equivalent
wesleywiser Jan 22, 2024
823e8b0
Allow disjoint flag in codegen test
nikic Jan 22, 2024
31f5f03
Remove uses of no-system-llvm
nikic Jan 23, 2024
f4f589a
Remove support for no-system-llvm
nikic Jan 23, 2024
31ecf34
Add the wasm32-wasi-preview2 target
rylev Dec 18, 2023
ba75970
privacy: Refactor top-level visiting in `TypePrivacyVisitor`
petrochenkov Jan 23, 2024
9676e18
Remove extra # from url
est31 Jan 23, 2024
0b1d7ff
Add `NonZero*::count_ones`
WaffleLapkin Nov 26, 2023
eabfe45
Add mw to review rotation and add some owner assignments
michaelwoerister Jan 24, 2024
db4cf5d
Add @davidtwco to debuginfo group in triage.toml
michaelwoerister Jan 24, 2024
61e2b41
Rollup merge of #114764 - pitaj:style-delimited-expressions, r=joshtr…
fmease Jan 24, 2024
3529d45
Rollup merge of #118326 - WaffleLapkin:nz_count_ones, r=scottmcm
fmease Jan 24, 2024
5a38754
Rollup merge of #119460 - Zalathar:improper-region, r=wesleywiser
fmease Jan 24, 2024
e0a4f43
Rollup merge of #119616 - rylev:wasm32-wasi-preview2, r=petrochenkov,…
fmease Jan 24, 2024
8bd126c
Rollup merge of #120185 - Zalathar:auto-derived, r=wesleywiser
fmease Jan 24, 2024
8290589
Rollup merge of #120265 - nikic:no-no-system-llvm, r=nagisa
fmease Jan 24, 2024
fee8f00
Rollup merge of #120284 - petrochenkov:typrivisit2, r=oli-obk
fmease Jan 24, 2024
7403d58
Rollup merge of #120285 - est31:remove_extra_pound, r=fmease
fmease Jan 24, 2024
8325f3d
Rollup merge of #120299 - michaelwoerister:review-rotation-update, r=…
fmease Jan 24, 2024
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
46 changes: 45 additions & 1 deletion compiler/rustc_mir_transform/src/coverage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ fn make_code_region(
start_line = source_map.doctest_offset_line(&file.name, start_line);
end_line = source_map.doctest_offset_line(&file.name, end_line);

Some(CodeRegion {
check_code_region(CodeRegion {
file_name,
start_line: start_line as u32,
start_col: start_col as u32,
Expand All @@ -338,6 +338,39 @@ fn make_code_region(
})
}

/// If `llvm-cov` sees a code region that is improperly ordered (end < start),
/// it will immediately exit with a fatal error. To prevent that from happening,
/// discard regions that are improperly ordered, or might be interpreted in a
/// way that makes them improperly ordered.
fn check_code_region(code_region: CodeRegion) -> Option<CodeRegion> {
let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;

// Line/column coordinates are supposed to be 1-based. If we ever emit
// coordinates of 0, `llvm-cov` might misinterpret them.
let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
// Coverage mappings use the high bit of `end_col` to indicate that a
// region is actually a "gap" region, so make sure it's unset.
let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
// If a region is improperly ordered (end < start), `llvm-cov` will exit
// with a fatal error, which is inconvenient for users and hard to debug.
let is_ordered = (start_line, start_col) <= (end_line, end_col);

if all_nonzero && end_col_has_high_bit_unset && is_ordered {
Some(code_region)
} else {
debug!(
?code_region,
?all_nonzero,
?end_col_has_high_bit_unset,
?is_ordered,
"Skipping code region that would be misinterpreted or rejected by LLVM"
);
// If this happens in a debug build, ICE to make it easier to notice.
debug_assert!(false, "Improper code region: {code_region:?}");
None
}
}

fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
// Only instrument functions, methods, and closures (not constants since they are evaluated
// at compile time by Miri).
Expand All @@ -351,7 +384,18 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
return false;
}

// Don't instrument functions with `#[automatically_derived]` on their
// enclosing impl block, on the assumption that most users won't care about
// coverage for derived impls.
if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
&& tcx.is_automatically_derived(impl_of)
{
trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
return false;
}

if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
return false;
}

Expand Down
90 changes: 27 additions & 63 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, PatKind};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
use rustc_middle::query::Providers;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, Const, GenericParamDefKind};
use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{kw, sym, Ident};
Expand Down Expand Up @@ -1064,29 +1064,22 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {

struct TypePrivacyVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
module_def_id: LocalModDefId,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
current_item: LocalDefId,
span: Span,
}

impl<'tcx> TypePrivacyVisitor<'tcx> {
/// Gets the type-checking results for the current body.
/// As this will ICE if called outside bodies, only call when working with
/// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
#[track_caller]
fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
self.maybe_typeck_results
.expect("`TypePrivacyVisitor::typeck_results` called outside of body")
}

fn item_is_accessible(&self, did: DefId) -> bool {
self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx)
self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
}

// Take node-id of an expression or pattern and check its type for privacy.
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
self.span = span;
let typeck_results = self.typeck_results();
let typeck_results = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
let result: ControlFlow<()> = try {
self.visit(typeck_results.node_type(id))?;
self.visit(typeck_results.node_args(id))?;
Expand All @@ -1107,35 +1100,13 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
}

impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
type NestedFilter = nested_filter::All;

/// We want to visit items in the context of their containing
/// module and so forth, so supply a crate for doing a deep walk.
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}

fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
// Don't visit nested modules, since we run a separate visitor walk
// for each module in `effective_visibilities`
}

fn visit_nested_body(&mut self, body: hir::BodyId) {
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let old_maybe_typeck_results =
self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
let body = self.tcx.hir().body(body);
self.visit_body(body);
self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
self.visit_body(self.tcx.hir().body(body_id));
self.maybe_typeck_results = old_maybe_typeck_results;
}

fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) {
match generic_arg {
hir::GenericArg::Type(t) => self.visit_ty(t),
hir::GenericArg::Infer(inf) => self.visit_infer(inf),
hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {}
}
}

fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
self.span = hir_ty.span;
if let Some(typeck_results) = self.maybe_typeck_results {
Expand Down Expand Up @@ -1163,19 +1134,19 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
return;
}
} else {
// We don't do anything for const infers here.
// FIXME: check types of const infers here.
}
} else {
bug!("visit_infer without typeck_results");
span_bug!(self.span, "`hir::InferArg` outside of a body");
}
intravisit::walk_inf(self, inf);
}

fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
self.span = trait_ref.path.span;
if self.maybe_typeck_results.is_none() {
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
// The traits' privacy in bodies is already checked as a part of trait object types.
if self.maybe_typeck_results.is_some() {
// Privacy of traits in bodies is checked as a part of trait object types.
} else {
let bounds = rustc_hir_analysis::hir_trait_to_predicates(
self.tcx,
trait_ref,
Expand Down Expand Up @@ -1223,7 +1194,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
hir::ExprKind::MethodCall(segment, ..) => {
// Method calls have to be checked specially.
self.span = segment.ident.span;
if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
let typeck_results = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
return;
}
Expand Down Expand Up @@ -1251,9 +1225,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
Res::Def(kind, def_id) => Some((kind, def_id)),
_ => None,
},
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.maybe_typeck_results
.and_then(|typeck_results| typeck_results.type_dependent_def(id)),
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
match self.maybe_typeck_results {
Some(typeck_results) => typeck_results.type_dependent_def(id),
// FIXME: Check type-relative associated types in signatures.
None => None,
}
}
};
let def = def.filter(|(kind, _)| {
matches!(
Expand Down Expand Up @@ -1307,15 +1285,6 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {

intravisit::walk_local(self, local);
}

// Check types in item interfaces.
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
let old_maybe_typeck_results = self.maybe_typeck_results.take();
intravisit::walk_item(self, item);
self.maybe_typeck_results = old_maybe_typeck_results;
self.current_item = orig_current_item;
}
}

impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
Expand Down Expand Up @@ -1785,13 +1754,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {

// Check privacy of explicitly written types and traits as well as
// inferred types of expressions and patterns.
let mut visitor = TypePrivacyVisitor {
tcx,
maybe_typeck_results: None,
current_item: module_def_id.to_local_def_id(),
span,
};
intravisit::walk_mod(&mut visitor, module, hir_id);
let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor);
}

fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ symbols! {
warn,
wasm_abi,
wasm_import_module,
wasm_preview2,
wasm_target_feature,
while_let,
windows,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,7 @@ supported_targets! {
("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
("wasm32-unknown-unknown", wasm32_unknown_unknown),
("wasm32-wasi", wasm32_wasi),
("wasm32-wasi-preview2", wasm32_wasi_preview2),
("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
("wasm64-unknown-unknown", wasm64_unknown_unknown),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@
//! best we can with this target. Don't start relying on too much here unless
//! you know what you're getting in to!

use crate::spec::{base, crt_objects, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
use crate::spec::{base, crt_objects, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};

pub fn target() -> Target {
let mut options = base::wasm::options();

options.families = cvs!["wasm", "wasi"];
options.os = "wasi".into();

options.add_pre_link_args(
Expand Down
64 changes: 64 additions & 0 deletions compiler/rustc_target/src/spec/targets/wasm32_wasi_preview2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! The `wasm32-wasi-preview2` target is the next evolution of the
//! wasm32-wasi target. While the wasi specification is still under
//! active development, the {review 2 iteration is considered an "island
//! of stability" that should allow users to rely on it indefinitely.
//!
//! The `wasi` target is a proposal to define a standardized set of WebAssembly
//! component imports that allow it to interoperate with the host system in a
//! standardized way. This set of imports is intended to empower WebAssembly
//! binaries with host capabilities such as filesystem access, network access, etc.
//!
//! Wasi Preview 2 relies on the WebAssembly component model which is an extension of
//! the core WebAssembly specification which allows interoperability between WebAssembly
//! modules (known as "components") through high-level, shared-nothing APIs instead of the
//! low-level, shared-everything linear memory model of the core WebAssembly specification.
//!
//! You can see more about wasi at <https://wasi.dev> and the component model at
//! <https://github.com/WebAssembly/component-model>.

use crate::spec::crt_objects;
use crate::spec::LinkSelfContainedDefault;
use crate::spec::{base, Target};

pub fn target() -> Target {
let mut options = base::wasm::options();

options.os = "wasi".into();
options.env = "preview2".into();
options.linker = Some("wasm-component-ld".into());

options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();

// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
options.link_self_contained = LinkSelfContainedDefault::True;

// Right now this is a bit of a workaround but we're currently saying that
// the target by default has a static crt which we're taking as a signal
// for "use the bundled crt". If that's turned off then the system's crt
// will be used, but this means that default usage of this target doesn't
// need an external compiler but it's still interoperable with an external
// compiler if configured correctly.
options.crt_static_default = true;
options.crt_static_respected = true;

// Allow `+crt-static` to create a "cdylib" output which is just a wasm file
// without a main function.
options.crt_static_allows_dylibs = true;

// WASI's `sys::args::init` function ignores its arguments; instead,
// `args::args()` makes the WASI API calls itself.
options.main_needs_argc_argv = false;

// And, WASI mangles the name of "main" to distinguish between different
// signatures.
options.entry_name = "__main_void".into();

Target {
llvm_target: "wasm32-unknown-unknown".into(),
pointer_width: 32,
data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
arch: "wasm32".into(),
options,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3155,7 +3155,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
// FIXME: we may suggest array::repeat instead
err.help("consider using `core::array::from_fn` to initialize the array");
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information");
err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
}

if self.tcx.sess.is_nightly_build()
Expand Down
37 changes: 37 additions & 0 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,43 @@ macro_rules! nonzero_integer {
unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 }
}

/// Returns the number of ones in the binary representation of `self`.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(non_zero_count_ones)]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
#[doc = concat!("# use std::num::{self, ", stringify!($Ty), "};")]
///
/// let one = num::NonZeroU32::new(1)?;
/// let three = num::NonZeroU32::new(3)?;
#[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")]
#[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")]
///
/// assert_eq!(a.count_ones(), one);
/// assert_eq!(b.count_ones(), three);
/// # Some(())
/// # }
/// ```
///
#[unstable(feature = "non_zero_count_ones", issue = "120287")]
#[rustc_const_unstable(feature = "non_zero_count_ones", issue = "120287")]
#[doc(alias = "popcount")]
#[doc(alias = "popcnt")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
pub const fn count_ones(self) -> NonZeroU32 {
// SAFETY:
// `self` is non-zero, which means it has at least one bit set, which means
// that the result of `count_ones` is non-zero.
unsafe { NonZeroU32::new_unchecked(self.get().count_ones()) }
}

nonzero_integer_signedness_dependent_methods! {
Self = $Ty,
Primitive = $signedness $Int,
Expand Down
Loading
Loading