about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-12 16:32:24 +0000
committerbors <bors@rust-lang.org>2022-08-12 16:32:24 +0000
commitf22819bcce4abaff7d1246a56eec493418f9f4ee (patch)
tree2fc9ac8d3bfe8d748c4b0971b05b472efca99120 /compiler
parent0068b8bf4b150b506ef0871be4e8652fd4308f84 (diff)
parent3bc30bb012889eeeb08d5241dfe64fc47ed33537 (diff)
downloadrust-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.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs4
-rw-r--r--compiler/rustc_errors/src/emitter.rs80
-rw-r--r--compiler/rustc_errors/src/lib.rs3
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs12
-rw-r--r--compiler/rustc_parse/src/parser/item.rs7
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs156
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 {