1
Fork 0

Auto merge of #100611 - matthiaskrgr:rollup-rxj10ur, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #100338 (when there are 3 or more return statements in the loop)
 - #100384 (Add support for generating unique profraw files by default when using `-C instrument-coverage`)
 - #100460 (Update the minimum external LLVM to 13)
 - #100567 (Add missing closing quote)
 - #100590 (Suggest adding an array length if possible)
 - #100600 (Rename Machine memory hooks to suggest when they run)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-16 05:13:38 +00:00
commit 8556e6620e
50 changed files with 321 additions and 338 deletions

View file

@ -48,7 +48,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability, Handler};
use rustc_errors::{struct_span_err, Applicability, Handler, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@ -2233,7 +2233,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
c.value.span,
"using `_` for array lengths is unstable",
)
.emit();
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
hir::ArrayLen::Body(self.lower_anon_const(c))
}
}

View file

@ -3,7 +3,6 @@ use crate::builder::Builder;
use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::llvm;
use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
@ -419,13 +418,6 @@ pub(crate) fn inline_asm_call<'ll>(
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
debug!("constraint verification result: {:?}", constraints_ok);
if constraints_ok {
if unwind && llvm_util::get_version() < (13, 0, 0) {
bx.cx.sess().span_fatal(
line_spans[0],
"unwinding from inline assembly is only supported on llvm >= 13.",
);
}
let v = llvm::LLVMRustInlineAsm(
fty,
asm.as_ptr().cast(),

View file

@ -5,7 +5,7 @@ use crate::back::profiling::{
use crate::base;
use crate::common;
use crate::consts;
use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use crate::llvm::{self, DiagnosticInfo, PassManager};
use crate::llvm_util;
use crate::type_::Type;
use crate::LlvmCodegenBackend;
@ -304,7 +304,6 @@ impl<'a> DiagnosticHandlers<'a> {
remark_passes.as_ptr(),
remark_passes.len(),
);
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data.cast());
DiagnosticHandlers { data, llcx, old_handler }
}
}
@ -312,9 +311,7 @@ impl<'a> DiagnosticHandlers<'a> {
impl<'a> Drop for DiagnosticHandlers<'a> {
fn drop(&mut self) {
use std::ptr::null_mut;
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut());
llvm::LLVMRustContextSetDiagnosticHandler(self.llcx, self.old_handler);
drop(Box::from_raw(self.data));
}
@ -342,16 +339,6 @@ fn report_inline_asm(
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
}
unsafe extern "C" fn inline_asm_handler(diag: &SMDiagnostic, user: *const c_void, cookie: c_uint) {
if user.is_null() {
return;
}
let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag);
report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source);
}
unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
if user.is_null() {
return;
@ -423,6 +410,14 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> {
.map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
}
fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
if config.instrument_coverage {
Some(CString::new("default_%m_%p.profraw").unwrap())
} else {
None
}
}
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
diag_handler: &Handler,
@ -438,6 +433,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
let pgo_use_path = get_pgo_use_path(config);
let pgo_sample_use_path = get_pgo_sample_use_path(config);
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
let instr_profile_output_path = get_instr_profile_output_path(config);
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
let sanitizer_options = if !is_lto {
Some(llvm::SanitizerOptions {
@ -488,6 +484,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
config.instrument_coverage,
instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
config.instrument_gcov,
pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
config.debug_info_for_profiling,

View file

@ -3,7 +3,6 @@ use crate::common::Funclet;
use crate::context::CodegenCx;
use crate::llvm::{self, BasicBlock, False};
use crate::llvm::{AtomicOrdering, AtomicRmwBinOp, SynchronizationScope};
use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
@ -1038,25 +1037,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
dst: &'ll Value,
cmp: &'ll Value,
src: &'ll Value,
mut order: rustc_codegen_ssa::common::AtomicOrdering,
order: rustc_codegen_ssa::common::AtomicOrdering,
failure_order: rustc_codegen_ssa::common::AtomicOrdering,
weak: bool,
) -> &'ll Value {
let weak = if weak { llvm::True } else { llvm::False };
if llvm_util::get_version() < (13, 0, 0) {
use rustc_codegen_ssa::common::AtomicOrdering::*;
// Older llvm has the pre-C++17 restriction on
// success and failure memory ordering,
// requiring the former to be at least as strong as the latter.
// So, for llvm 12, we upgrade the success ordering to a stronger
// one if necessary.
match (order, failure_order) {
(Relaxed, Acquire) => order = Acquire,
(Release, Acquire) => order = AcquireRelease,
(_, SequentiallyConsistent) => order = SequentiallyConsistent,
_ => {}
}
}
unsafe {
llvm::LLVMRustBuildAtomicCmpXchg(
self.llbuilder,
@ -1444,51 +1429,37 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
}
}
fn fptoint_sat_broken_in_llvm(&self) -> bool {
match self.tcx.sess.target.arch.as_ref() {
// FIXME - https://bugs.llvm.org/show_bug.cgi?id=50083
"riscv64" => llvm_util::get_version() < (13, 0, 0),
_ => false,
}
}
fn fptoint_sat(
&mut self,
signed: bool,
val: &'ll Value,
dest_ty: &'ll Type,
) -> Option<&'ll Value> {
if !self.fptoint_sat_broken_in_llvm() {
let src_ty = self.cx.val_ty(val);
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector
{
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
(
self.cx.element_type(src_ty),
self.cx.element_type(dest_ty),
Some(self.cx.vector_length(src_ty)),
)
} else {
(src_ty, dest_ty, None)
};
let float_width = self.cx.float_width(float_ty);
let int_width = self.cx.int_width(int_ty);
let instr = if signed { "fptosi" } else { "fptoui" };
let name = if let Some(vector_length) = vector_length {
format!(
"llvm.{}.sat.v{}i{}.v{}f{}",
instr, vector_length, int_width, vector_length, float_width
)
} else {
format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
};
let f =
self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
let src_ty = self.cx.val_ty(val);
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
(
self.cx.element_type(src_ty),
self.cx.element_type(dest_ty),
Some(self.cx.vector_length(src_ty)),
)
} else {
None
}
(src_ty, dest_ty, None)
};
let float_width = self.cx.float_width(float_ty);
let int_width = self.cx.int_width(int_ty);
let instr = if signed { "fptosi" } else { "fptoui" };
let name = if let Some(vector_length) = vector_length {
format!(
"llvm.{}.sat.v{}i{}.v{}f{}",
instr, vector_length, int_width, vector_length, float_width
)
} else {
format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
};
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
}
pub(crate) fn landing_pad(

View file

@ -142,17 +142,6 @@ pub unsafe fn create_module<'ll>(
let mut target_data_layout = sess.target.data_layout.to_string();
let llvm_version = llvm_util::get_version();
if llvm_version < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
}
if sess.target.arch == "wasm32" {
target_data_layout = "e-m:e-p:32:32-i64:64-n32:64-S128".to_string();
}
if sess.target.arch == "wasm64" {
target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
}
}
if llvm_version < (14, 0, 0) {
if sess.target.llvm_target == "i686-pc-windows-msvc"
|| sess.target.llvm_target == "i586-pc-windows-msvc"

View file

@ -2360,6 +2360,7 @@ extern "C" {
PGOGenPath: *const c_char,
PGOUsePath: *const c_char,
InstrumentCoverage: bool,
InstrProfileOutput: *const c_char,
InstrumentGCOV: bool,
PGOSampleUsePath: *const c_char,
DebugInfoForProfiling: bool,
@ -2423,12 +2424,6 @@ extern "C" {
cookie_out: &mut c_uint,
) -> &'a SMDiagnostic;
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
H: InlineAsmDiagHandlerTy,
CX: *mut c_void,
);
#[allow(improper_ctypes)]
pub fn LLVMRustUnpackSMDiagnostic(
d: &SMDiagnostic,

View file

@ -92,16 +92,6 @@ unsafe fn configure_llvm(sess: &Session) {
add("-generate-arange-section", false);
}
// Disable the machine outliner by default in LLVM versions 11 and LLVM
// version 12, where it leads to miscompilation.
//
// Ref:
// - https://github.com/rust-lang/rust/issues/85351
// - https://reviews.llvm.org/D103167
if llvm_util::get_version() < (13, 0, 0) {
add("-enable-machine-outliner=never", false);
}
match sess.opts.unstable_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
MergeFunctions::Aliases => {

View file

@ -343,7 +343,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
/// need to mutate.
#[inline(always)]
fn memory_read(
fn before_memory_read(
_tcx: TyCtxt<'tcx>,
_machine: &Self,
_alloc_extra: &Self::AllocExtra,
@ -355,7 +355,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// Hook for performing extra checks on a memory write access.
#[inline(always)]
fn memory_written(
fn before_memory_write(
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
@ -367,7 +367,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// Hook for performing extra operations on a memory deallocation.
#[inline(always)]
fn memory_deallocated(
fn before_memory_deallocation(
_tcx: TyCtxt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,

View file

@ -327,7 +327,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Let the machine take some extra action
let size = alloc.size();
M::memory_deallocated(
M::before_memory_deallocation(
*self.tcx,
&mut self.machine,
&mut alloc.extra,
@ -575,7 +575,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
)?;
if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
let range = alloc_range(offset, size);
M::memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
M::before_memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?;
Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id }))
} else {
// Even in this branch we have to be sure that we actually access the allocation, in
@ -641,7 +641,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?;
let range = alloc_range(offset, size);
M::memory_written(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?;
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
} else {
Ok(None)
@ -1078,7 +1078,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
let src_range = alloc_range(src_offset, size);
M::memory_read(*tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), src_range)?;
M::before_memory_read(
*tcx,
&self.machine,
&src_alloc.extra,
(src_alloc_id, src_prov),
src_range,
)?;
// We need the `dest` ptr for the next operation, so we get it now.
// We already did the source checks and called the hooks so we are good to return early.
let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else {
@ -1103,7 +1109,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Destination alloc preparations and access hooks.
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
let dest_range = alloc_range(dest_offset, size * num_copies);
M::memory_written(
M::before_memory_write(
*tcx,
extra,
&mut dest_alloc.extra,

View file

@ -457,6 +457,7 @@ struct HandlerInner {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum StashKey {
ItemNoType,
UnderscoreForArrayLengths,
}
fn default_track_diagnostic(_: &Diagnostic) {}

View file

@ -277,7 +277,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing),
ungated!(
should_panic, Normal,
template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), FutureWarnFollowing,
template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing,
),
// FIXME(Centril): This can be used on stable but shouldn't.
ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing),

View file

@ -24,17 +24,10 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
const char* const Filenames[],
size_t FilenamesLen,
RustStringRef BufferOut) {
#if LLVM_VERSION_GE(13,0)
SmallVector<std::string,32> FilenameRefs;
for (size_t i = 0; i < FilenamesLen; i++) {
FilenameRefs.push_back(std::string(Filenames[i]));
}
#else
SmallVector<StringRef,32> FilenameRefs;
for (size_t i = 0; i < FilenamesLen; i++) {
FilenameRefs.push_back(StringRef(Filenames[i]));
}
#endif
auto FilenamesWriter = coverage::CoverageFilenamesSectionWriter(
makeArrayRef(FilenameRefs));
RawRustStringOstream OS(BufferOut);
@ -109,9 +102,5 @@ extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
#if LLVM_VERSION_GE(13, 0)
return coverage::CovMapVersion::Version6;
#else
return coverage::CovMapVersion::Version5;
#endif
}

View file

@ -822,7 +822,8 @@ LLVMRustOptimizeWithNewPassManager(
bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers,
LLVMRustSanitizerOptions *SanitizerOptions,
const char *PGOGenPath, const char *PGOUsePath,
bool InstrumentCoverage, bool InstrumentGCOV,
bool InstrumentCoverage, const char *InstrProfileOutput,
bool InstrumentGCOV,
const char *PGOSampleUsePath, bool DebugInfoForProfiling,
void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
@ -869,19 +870,11 @@ LLVMRustOptimizeWithNewPassManager(
PGOOptions::NoCSAction, DebugInfoForProfiling);
}
#if LLVM_VERSION_GE(13, 0)
PassBuilder PB(TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
#else
PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM(DebugPassManager);
FunctionAnalysisManager FAM(DebugPassManager);
CGSCCAnalysisManager CGAM(DebugPassManager);
ModuleAnalysisManager MAM(DebugPassManager);
#endif
FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
@ -922,8 +915,11 @@ LLVMRustOptimizeWithNewPassManager(
if (InstrumentCoverage) {
PipelineStartEPCallbacks.push_back(
[](ModulePassManager &MPM, OptimizationLevel Level) {
[InstrProfileOutput](ModulePassManager &MPM, OptimizationLevel Level) {
InstrProfOptions Options;
if (InstrProfileOutput) {
Options.InstrProfileOutput = InstrProfileOutput;
}
MPM.addPass(InstrProfiling(Options, false));
}
);
@ -1015,11 +1011,7 @@ LLVMRustOptimizeWithNewPassManager(
}
}
#if LLVM_VERSION_GE(13, 0)
ModulePassManager MPM;
#else
ModulePassManager MPM(DebugPassManager);
#endif
bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
if (!NoPrepopulatePasses) {
// The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
@ -1434,17 +1426,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
};
#if LLVM_VERSION_GE(13,0)
// Uses FromPrevailing visibility scheme which works for many binary
// formats. We probably could and should use ELF visibility scheme for many of
// our targets, however.
lto::Config conf;
thinLTOResolvePrevailingInIndex(conf, Ret->Index, isPrevailing, recordNewLinkage,
Ret->GUIDPreservedSymbols);
#else
thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage,
Ret->GUIDPreservedSymbols);
#endif
// Here we calculate an `ExportedGUIDs` set for use in the `isExported`
// callback below. This callback below will dictate the linkage for all
// summaries in the index, and we basically just only want to ensure that dead

View file

@ -413,18 +413,12 @@ LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target,
LLVMValueRef Old, LLVMValueRef Source,
LLVMAtomicOrdering Order,
LLVMAtomicOrdering FailureOrder, LLVMBool Weak) {
#if LLVM_VERSION_GE(13,0)
// Rust probably knows the alignment of the target value and should be able to
// specify something more precise than MaybeAlign here. See also
// https://reviews.llvm.org/D97224 which may be a useful reference.
AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg(
unwrap(Target), unwrap(Old), unwrap(Source), llvm::MaybeAlign(), fromRust(Order),
fromRust(FailureOrder));
#else
AtomicCmpXchgInst *ACXI = unwrap(B)->CreateAtomicCmpXchg(
unwrap(Target), unwrap(Old), unwrap(Source), fromRust(Order),
fromRust(FailureOrder));
#endif
ACXI->setWeak(Weak);
return wrap(ACXI);
}
@ -472,19 +466,11 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
char *Constraints, size_t ConstraintsLen,
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
#if LLVM_VERSION_GE(13, 0)
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
StringRef(AsmString, AsmStringLen),
StringRef(Constraints, ConstraintsLen),
HasSideEffects, IsAlignStack,
fromRust(Dialect), CanThrow));
#else
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
StringRef(AsmString, AsmStringLen),
StringRef(Constraints, ConstraintsLen),
HasSideEffects, IsAlignStack,
fromRust(Dialect)));
#endif
}
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
@ -1274,10 +1260,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
return LLVMRustDiagnosticKind::Linker;
case DK_Unsupported:
return LLVMRustDiagnosticKind::Unsupported;
#if LLVM_VERSION_GE(13, 0)
case DK_SrcMgr:
return LLVMRustDiagnosticKind::SrcMgr;
#endif
default:
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
? LLVMRustDiagnosticKind::OptimizationRemarkOther
@ -1351,30 +1335,11 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
#if LLVM_VERSION_LT(13, 0)
using LLVMInlineAsmDiagHandlerTy = LLVMContext::InlineAsmDiagHandlerTy;
#else
using LLVMInlineAsmDiagHandlerTy = void*;
#endif
extern "C" void LLVMRustSetInlineAsmDiagnosticHandler(
LLVMContextRef C, LLVMInlineAsmDiagHandlerTy H, void *CX) {
// Diagnostic handlers were unified in LLVM change 5de2d189e6ad, so starting
// with LLVM 13 this function is gone.
#if LLVM_VERSION_LT(13, 0)
unwrap(C)->setInlineAsmDiagnosticHandler(H, CX);
#endif
}
extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(
LLVMDiagnosticInfoRef DI, unsigned *Cookie) {
#if LLVM_VERSION_GE(13, 0)
llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI));
*Cookie = SM->getLocCookie();
return wrap(&SM->getSMDiag());
#else
report_fatal_error("Shouldn't get called on older versions");
#endif
}
extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef,

View file

@ -1594,7 +1594,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
let mut span: MultiSpan = vec![loop_span].into();
span.push_span_label(loop_span, "this might have zero elements to iterate on");
for ret_expr in ret_exprs {
const MAXITER: usize = 3;
let iter = ret_exprs.iter().take(MAXITER);
for ret_expr in iter {
span.push_span_label(
ret_expr.span,
"if the loop doesn't execute, this value would never get returned",
@ -1604,6 +1606,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
span,
"the function expects a value to always be returned, but loops might run zero times",
);
if MAXITER < ret_exprs.len() {
err.note(&format!(
"if the loop doesn't execute, {} other values would never get returned",
ret_exprs.len() - MAXITER
));
}
err.help(
"return a value for the case when the loop has zero elements to iterate on, or \
consider changing the return type to account for that possibility",

View file

@ -28,7 +28,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
ErrorGuaranteed,
ErrorGuaranteed, StashKey,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
@ -1307,7 +1307,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: expr.span,
})
};
self.tcx.mk_array(element_ty, args.len() as u64)
let array_len = args.len() as u64;
self.suggest_array_len(expr, array_len);
self.tcx.mk_array(element_ty, array_len)
}
fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) {
if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(expr.hir_id) {
let ty = match self.tcx.hir().find(parent_hir_id) {
Some(
hir::Node::Local(hir::Local { ty: Some(ty), .. })
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }),
) => Some(ty),
_ => None,
};
if let Some(ty) = ty
&& let hir::TyKind::Array(_, length) = ty.kind
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
&& let Some(span) = self.tcx.hir().opt_span(hir_id)
{
match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
Some(mut err) => {
err.span_suggestion(
span,
"consider specifying the array length",
array_len,
Applicability::MaybeIncorrect,
);
err.emit();
}
None => ()
}
}
}
}
fn check_expr_const_block(
@ -1333,10 +1365,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
element: &'tcx hir::Expr<'tcx>,
count: &'tcx hir::ArrayLen,
expected: Expectation<'tcx>,
_expr: &'tcx hir::Expr<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
let count = self.array_length_to_const(count);
if let Some(count) = count.try_eval_usize(tcx, self.param_env) {
self.suggest_array_len(expr, count);
}
let uty = match expected {
ExpectHasType(uty) => match *uty.kind() {