diff options
| author | bors <bors@rust-lang.org> | 2022-08-12 16:32:24 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-08-12 16:32:24 +0000 |
| commit | f22819bcce4abaff7d1246a56eec493418f9f4ee (patch) | |
| tree | 2fc9ac8d3bfe8d748c4b0971b05b472efca99120 /compiler | |
| parent | 0068b8bf4b150b506ef0871be4e8652fd4308f84 (diff) | |
| parent | 3bc30bb012889eeeb08d5241dfe64fc47ed33537 (diff) | |
| download | rust-f22819bcce4abaff7d1246a56eec493418f9f4ee.tar.gz rust-f22819bcce4abaff7d1246a56eec493418f9f4ee.zip | |
Auto merge of #100456 - Dylan-DPC:rollup-fn17z9f, r=Dylan-DPC
Rollup of 9 pull requests Successful merges: - #100022 (Optimize thread ID generation) - #100030 (cleanup code w/ pointers in std a little) - #100229 (add -Zextra-const-ub-checks to enable more UB checking in const-eval) - #100247 (Generalize trait object generic param check to aliases.) - #100255 (Adding more verbose documentation for `std::fmt::Write`) - #100366 (errors: don't fail on broken primary translations) - #100396 (Suggest const and static for global variable) - #100409 (rustdoc: don't generate DOM element for operator) - #100443 (Add two let else regression tests) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/machine.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/machine.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/validity.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 80 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/const_prop.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_session/src/options.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/astconv/mod.rs | 156 |
9 files changed, 162 insertions, 124 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a3d..684877cae76 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + #[inline(always)] + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + + #[inline(always)] + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799fa..9b9919fcc2a 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -437,24 +437,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type FrameExtra = (); #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - - #[inline(always)] fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { // We do not support `force_int`. false } #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - - #[inline(always)] fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f6717721fb..f1b1855c3ec 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's + // still correct to not use `ctfe_mode`: that mode is for validation of the final constant + // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking + // recurse through references which, for now, we don't want here, either. self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 61d953cd6f1..753e2f07c04 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -273,40 +273,58 @@ pub trait Emitter { DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), }; - let bundle = match self.fluent_bundle() { - Some(bundle) if bundle.has_message(&identifier) => bundle, - _ => self.fallback_fluent_bundle(), - }; + let translate_with_bundle = |bundle: &'a FluentBundle| -> Option<(Cow<'_, str>, Vec<_>)> { + let message = bundle.get_message(&identifier)?; + let value = match attr { + Some(attr) => message.get_attribute(attr)?.value(), + None => message.value()?, + }; + debug!(?message, ?value); - let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle"); - let value = match attr { - Some(attr) => { - if let Some(attr) = message.get_attribute(attr) { - attr.value() - } else { - panic!("missing attribute `{attr}` in fluent message `{identifier}`") - } - } - None => { - if let Some(value) = message.value() { - value - } else { - panic!("missing value in fluent message `{identifier}`") - } - } + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(&args), &mut errs); + debug!(?translated, ?errs); + Some((translated, errs)) }; - let mut err = vec![]; - let translated = bundle.format_pattern(value, Some(&args), &mut err); - trace!(?translated, ?err); - debug_assert!( - err.is_empty(), - "identifier: {:?}, args: {:?}, errors: {:?}", - identifier, - args, - err - ); - translated + self.fluent_bundle() + .and_then(|bundle| translate_with_bundle(bundle)) + // If `translate_with_bundle` returns `None` with the primary bundle, this is likely + // just that the primary bundle doesn't contain the message being translated, so + // proceed to the fallback bundle. + // + // However, when errors are produced from translation, then that means the translation + // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided). + // + // In debug builds, assert so that compiler devs can spot the broken translation and + // fix it.. + .inspect(|(_, errs)| { + debug_assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + }) + // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so + // just hide it and try with the fallback bundle. + .filter(|(_, errs)| errs.is_empty()) + .or_else(|| translate_with_bundle(self.fallback_fluent_bundle())) + .map(|(translated, errs)| { + // Always bail out for errors with the fallback bundle. + assert!( + errs.is_empty(), + "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}", + identifier, + attr, + args, + errs + ); + translated + }) + .expect("failed to find message in primary or fallback fluent bundles") } /// Formats the substitutions of the primary_span diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 15c1858023d..f83e972efd5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,9 +6,10 @@ #![feature(drain_filter)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] +#![feature(adt_const_params)] #![feature(let_else)] #![feature(never_type)] -#![feature(adt_const_params)] +#![feature(result_option_inspect)] #![feature(rustc_attrs)] #![allow(incomplete_features)] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 98016659a05..1c087b93b49 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; + #[inline(always)] + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, _instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 72c23776d33..197c0384898 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -68,7 +68,12 @@ impl<'a> Parser<'a> { if !self.maybe_consume_incorrect_semicolon(&items) { let msg = &format!("expected item, found {token_str}"); let mut err = self.struct_span_err(self.token.span, msg); - err.span_label(self.token.span, "expected item"); + let label = if self.is_kw_followed_by_ident(kw::Let) { + "consider using `const` or `static` instead of `let` for global variables" + } else { + "expected item" + }; + err.span_label(self.token.span, label); return Err(err); } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c208d..0032dd7d113 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1310,6 +1310,8 @@ options! { "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 758f1ef9766..1e6cb53f3ee 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -44,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{ }; use rustc_trait_selection::traits::wf::object_region_bounds; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; use std::slice; @@ -368,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.intern_substs(&[]), arg_count); } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec<Symbol>, inferred_params: Vec<Span>, infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - } } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -500,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); - tcx.ty_error().into() - } else { - // This is a default type parameter. - let substs = substs.unwrap(); - if substs.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { - // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error().into(); - } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) - .into() + let substs = substs.unwrap(); + if substs.iter().any(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.references_error(), + _ => false, + }) { + // Avoid ICE #86756 when type error recovery goes awry. + return tcx.ty_error().into(); } + self.astconv + .normalize_ty( + self.span, + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), + ) + .into() } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() + self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() @@ -564,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, span, generic_args, - missing_type_params: vec![], inferred_params: vec![], infer_args, - is_object, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -579,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - debug!( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", generics, self_ty, substs @@ -1490,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { + debug!(?ty); + if ty == dummy_self { + let param = &generics.params[index]; + missing_type_params.push(param.name); + tcx.ty_error().into() + } else if ty.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + tcx.ty_error().into() + } else { + arg + } + } else { + arg + } + }) + .collect(); + let substs = tcx.intern_substs(&substs[..]); + + let span = i.bottom().1; + let empty_generic_args = trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_kind(def_id).descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), ); + err.emit(); } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { if b.projection_ty.self_ty() != dummy_self { |
