diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index d323c16165bba..5ceeb72f2912a 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -9,6 +9,7 @@ use rustc_ast::{self as ast, *}; use rustc_hir as hir; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::GenericArg; +use rustc_middle::span_bug; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; @@ -285,7 +286,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (start, end) = match self.resolver.get_lifetime_res(segment_id) { Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end), None => return, - Some(_) => panic!(), + Some(res) => { + span_bug!(path_span, "expected an elided lifetime to insert. found {res:?}") + } }; let expected_lifetimes = end.as_usize() - start.as_usize(); debug!(expected_lifetimes); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 28bd6c2111b72..790b583134c0d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -225,7 +225,8 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here .closure = closures cannot have `~const` trait bounds .function = this function is not `const`, so it cannot have `~const` trait bounds .trait = this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - .impl = this impl is not `const`, so it cannot have `~const` trait bounds + .trait_impl = this impl is not `const`, so it cannot have `~const` trait bounds + .impl = inherent impls cannot have `~const` trait bounds .object = trait objects cannot have `~const` trait bounds .item = this item cannot have `~const` trait bounds diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9db72c15941e2..e757132108dfa 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -41,6 +41,7 @@ enum DisallowTildeConstContext<'a> { TraitObject, Fn(FnKind<'a>), Trait(Span), + TraitImpl(Span), Impl(Span), Item, } @@ -836,7 +837,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.visit_vis(&item.vis); this.visit_ident(item.ident); let disallowed = matches!(constness, Const::No) - .then(|| DisallowTildeConstContext::Impl(item.span)); + .then(|| DisallowTildeConstContext::TraitImpl(item.span)); this.with_tilde_const(disallowed, |this| this.visit_generics(generics)); this.visit_trait_ref(t); this.visit_ty(self_ty); @@ -889,7 +890,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.visit_vis(&item.vis); self.visit_ident(item.ident); - self.with_tilde_const(None, |this| this.visit_generics(generics)); + self.with_tilde_const(Some(DisallowTildeConstContext::Impl(item.span)), |this| { + this.visit_generics(generics) + }); self.visit_ty(self_ty); walk_list!(self, visit_assoc_item, items, AssocCtxt::Impl); walk_list!(self, visit_attribute, &item.attrs); @@ -1215,7 +1218,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &DisallowTildeConstContext::Trait(span) => { errors::TildeConstReason::Trait { span } } + &DisallowTildeConstContext::TraitImpl(span) => { + errors::TildeConstReason::TraitImpl { span } + } &DisallowTildeConstContext::Impl(span) => { + // FIXME(effects): Consider providing a help message or even a structured + // suggestion for moving such bounds to the assoc const fns if available. errors::TildeConstReason::Impl { span } } DisallowTildeConstContext::TraitObject => { diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 928bf19759ada..4283fc7c07d1f 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -563,6 +563,11 @@ pub enum TildeConstReason { #[primary_span] span: Span, }, + #[note(ast_passes_trait_impl)] + TraitImpl { + #[primary_span] + span: Span, + }, #[note(ast_passes_impl)] Impl { #[primary_span] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4a2a693862b13..d6c15ec35b603 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1597,7 +1597,9 @@ impl<'a> State<'a> { } match bound { ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt), - _ => panic!(), + _ => { + panic!("expected a lifetime bound, found a trait bound") + } } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 8386f067bafba..0befbb5a39be3 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -85,6 +85,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let bx = self; + match coverage.kind { + // Marker statements have no effect during codegen, + // so return early and don't create `func_coverage`. + CoverageKind::SpanMarker => return, + // Match exhaustively to ensure that newly-added kinds are classified correctly. + CoverageKind::CounterIncrement { .. } | CoverageKind::ExpressionUsed { .. } => {} + } + let Some(function_coverage_info) = bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref() else { @@ -100,9 +108,9 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { let Coverage { kind } = coverage; match *kind { - // Span markers are only meaningful during MIR instrumentation, - // and have no effect during codegen. - CoverageKind::SpanMarker => {} + CoverageKind::SpanMarker => unreachable!( + "unexpected marker statement {kind:?} should have caused an early return" + ), CoverageKind::CounterIncrement { id } => { func_coverage.mark_counter_id_seen(id); // We need to explicitly drop the `RefMut` before calling into `instrprof_increment`, diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index bc0e3a8280636..b683e1b45a8d1 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -158,12 +158,13 @@ pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a file.symbols().find(|sym| sym.name() == Ok(AIX_METADATA_SYMBOL_NAME)) { let offset = metadata_symbol.address() as usize; - if offset < 8 { + // The offset specifies the location of rustc metadata in the .info section of XCOFF. + // Each string stored in .info section of XCOFF is preceded by a 4-byte length field. + if offset < 4 { return Err(format!("Invalid metadata symbol offset: {offset}")); } - // The offset specifies the location of rustc metadata in the comment section. - // The metadata is preceded by a 8-byte length field. - let len = u64::from_le_bytes(info_data[(offset - 8)..offset].try_into().unwrap()) as usize; + // XCOFF format uses big-endian byte order. + let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize; if offset + len > (info_data.len() as usize) { return Err(format!( "Metadata at offset {offset} with size {len} is beyond .info section" @@ -478,9 +479,12 @@ pub fn create_wrapper_file( file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text); file.section_mut(section).flags = SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 }; - - let len = data.len() as u64; - let offset = file.append_section_data(section, &len.to_le_bytes(), 1); + // Encode string stored in .info section of XCOFF. + // FIXME: The length of data here is not guaranteed to fit in a u32. + // We may have to split the data into multiple pieces in order to + // store in .info section. + let len: u32 = data.len().try_into().unwrap(); + let offset = file.append_section_data(section, &len.to_be_bytes(), 1); // Add a symbol referring to the data in .info section. file.add_symbol(Symbol { name: AIX_METADATA_SYMBOL_NAME.into(), @@ -599,12 +603,12 @@ pub fn create_compressed_metadata_file_for_xcoff( section: SymbolSection::Section(data_section), flags: SymbolFlags::None, }); - let len = data.len() as u64; - let offset = file.append_section_data(section, &len.to_le_bytes(), 1); + let len: u32 = data.len().try_into().unwrap(); + let offset = file.append_section_data(section, &len.to_be_bytes(), 1); // Add a symbol referring to the rustc metadata. file.add_symbol(Symbol { name: AIX_METADATA_SYMBOL_NAME.into(), - value: offset + 8, // The metadata is preceded by a 8-byte length field. + value: offset + 4, // The metadata is preceded by a 4-byte length field. size: 0, kind: SymbolKind::Unknown, scope: SymbolScope::Dynamic, diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 65a0924f1c9fb..709d1fdc21a08 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -99,12 +99,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn inject_counters(&'a mut self) { //////////////////////////////////////////////////// // Compute coverage spans from the `CoverageGraph`. - let coverage_spans = CoverageSpans::generate_coverage_spans( + let Some(coverage_spans) = CoverageSpans::generate_coverage_spans( self.mir_body, self.fn_sig_span, self.body_span, &self.basic_coverage_blocks, - ); + ) else { + // No relevant spans were found in MIR, so skip instrumenting this function. + return; + }; //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 05ad14f1525cd..462e54c386c7a 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -15,12 +15,16 @@ pub(super) struct CoverageSpans { } impl CoverageSpans { + /// Extracts coverage-relevant spans from MIR, and associates them with + /// their corresponding BCBs. + /// + /// Returns `None` if no coverage-relevant spans could be extracted. pub(super) fn generate_coverage_spans( mir_body: &mir::Body<'_>, fn_sig_span: Span, body_span: Span, basic_coverage_blocks: &CoverageGraph, - ) -> Self { + ) -> Option { let coverage_spans = CoverageSpansGenerator::generate_coverage_spans( mir_body, fn_sig_span, @@ -28,13 +32,17 @@ impl CoverageSpans { basic_coverage_blocks, ); + if coverage_spans.is_empty() { + return None; + } + // Group the coverage spans by BCB, with the BCBs in sorted order. let mut bcb_to_spans = IndexVec::from_elem_n(Vec::new(), basic_coverage_blocks.num_nodes()); for CoverageSpan { bcb, span, .. } in coverage_spans { bcb_to_spans[bcb].push(span); } - Self { bcb_to_spans } + Some(Self { bcb_to_spans }) } pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs index fbfc5c22fcb34..4c7029c4e520e 100644 --- a/compiler/rustc_span/src/caching_source_map_view.rs +++ b/compiler/rustc_span/src/caching_source_map_view.rs @@ -117,7 +117,7 @@ impl<'sm> CachingSourceMapView<'sm> { self.time_stamp += 1; // Check if lo and hi are in the cached lines. - let lo_cache_idx = self.cache_entry_index(span_data.lo); + let lo_cache_idx: isize = self.cache_entry_index(span_data.lo); let hi_cache_idx = self.cache_entry_index(span_data.hi); if lo_cache_idx != -1 && hi_cache_idx != -1 { @@ -205,7 +205,9 @@ impl<'sm> CachingSourceMapView<'sm> { (lo_cache_idx as usize, oldest) } _ => { - panic!(); + panic!( + "the case of neither value being equal to -1 was handled above and the function returns." + ); } }; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 09dfb0caeecb3..4248454368644 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -309,14 +309,16 @@ impl File { && unsafe { c::GetLastError() } == c::ERROR_ALREADY_EXISTS { unsafe { - // Setting the allocation size to zero also sets the - // EOF position to zero. - let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; + // This originally used `FileAllocationInfo` instead of + // `FileEndOfFileInfo` but that wasn't supported by WINE. + // It's arguable which fits the semantics of `OpenOptions` + // better so let's just use the more widely supported method. + let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), - c::FileAllocationInfo, - ptr::addr_of!(alloc).cast::(), - mem::size_of::() as u32, + c::FileEndOfFileInfo, + ptr::addr_of!(eof).cast::(), + mem::size_of::() as u32, ); if result == 0 { return Err(io::Error::last_os_error()); diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map new file mode 100644 index 0000000000000..5277267ec1b01 --- /dev/null +++ b/tests/coverage/no_spans_if_not.cov-map @@ -0,0 +1,8 @@ +Function name: no_spans_if_not::main +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] +Number of files: 1 +- file 0 => global file 1 +Number of expressions: 0 +Number of file 0 mappings: 1 +- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) + diff --git a/tests/coverage/no_spans_if_not.coverage b/tests/coverage/no_spans_if_not.coverage new file mode 100644 index 0000000000000..1b6bbc75a04e4 --- /dev/null +++ b/tests/coverage/no_spans_if_not.coverage @@ -0,0 +1,30 @@ + LL| |// edition: 2021 + LL| | + LL| |// If the span extractor can't find any relevant spans for a function, + LL| |// but the function contains coverage span-marker statements (e.g. inserted + LL| |// for `if !`), coverage codegen may think that it is instrumented and + LL| |// consequently complain that it has no spans. + LL| |// + LL| |// Regression test for , + LL| |// "A used function should have had coverage mapping data but did not". + LL| | + LL| 1|fn main() { + LL| 1| affected_function(); + LL| 1|} + LL| | + LL| |macro_rules! macro_that_defines_a_function { + LL| | (fn $name:ident () $body:tt) => { + LL| | fn $name () $body + LL| | } + LL| |} + LL| | + LL| |macro_that_defines_a_function! { + LL| | fn affected_function() { + LL| | if !false { + LL| | () + LL| | } else { + LL| | () + LL| | } + LL| | } + LL| |} + diff --git a/tests/coverage/no_spans_if_not.rs b/tests/coverage/no_spans_if_not.rs new file mode 100644 index 0000000000000..2bbdc11cd5e59 --- /dev/null +++ b/tests/coverage/no_spans_if_not.rs @@ -0,0 +1,29 @@ +// edition: 2021 + +// If the span extractor can't find any relevant spans for a function, +// but the function contains coverage span-marker statements (e.g. inserted +// for `if !`), coverage codegen may think that it is instrumented and +// consequently complain that it has no spans. +// +// Regression test for , +// "A used function should have had coverage mapping data but did not". + +fn main() { + affected_function(); +} + +macro_rules! macro_that_defines_a_function { + (fn $name:ident () $body:tt) => { + fn $name () $body + } +} + +macro_that_defines_a_function! { + fn affected_function() { + if !false { + () + } else { + () + } + } +} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs index bbe1194f7a315..5ecb75094f03d 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs @@ -52,4 +52,7 @@ trait Child1 where Self: ~const Trait {} //~ ERROR `~const` is not allowed // non-const impl impl Trait for T {} //~ ERROR `~const` is not allowed +// inherent impl (regression test for issue #117004) +impl Struct {} //~ ERROR `~const` is not allowed + fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr index c6e18924fd81c..497ec5bcf84d8 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr @@ -194,6 +194,18 @@ note: this impl is not `const`, so it cannot have `~const` trait bounds LL | impl Trait for T {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: `~const` is not allowed here + --> $DIR/tilde-const-invalid-places.rs:56:9 + | +LL | impl Struct {} + | ^^^^^^ + | +note: inherent impls cannot have `~const` trait bounds + --> $DIR/tilde-const-invalid-places.rs:56:1 + | +LL | impl Struct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0658]: generic const items are experimental --> $DIR/tilde-const-invalid-places.rs:19:15 | @@ -239,6 +251,6 @@ LL | type Type = (); = note: see issue #8995 for more information = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs index fbdc3a4f370cb..bfd9fe42e67ae 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs @@ -1,5 +1,4 @@ -// known-bug: #110395 -// FIXME check-pass +// check-pass #![feature(const_trait_impl, effects)] #[const_trait] @@ -9,8 +8,8 @@ trait Foo { struct Bar(T); -impl Bar { - const fn foo(&self) { +impl Bar { + const fn foo(&self) where T: ~const Foo { self.0.foo() } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr deleted file mode 100644 index 0925bfa7e576e..0000000000000 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/tilde_const_on_impl_bound.rs:14:9 - | -LL | self.0.foo() - | ^^^^^^^^^^^^ expected `host`, found `true` - | - = note: expected constant `host` - found constant `true` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`.