about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs25
-rw-r--r--compiler/rustc_lint/messages.ftl6
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs (renamed from compiler/rustc_lint/src/cast_ref_to_mut.rs)15
-rw-r--r--compiler/rustc_lint/src/types.rs104
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs15
7 files changed, 100 insertions, 77 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index cd56f85cccd..8ac86fa4b26 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -13,6 +13,7 @@ use std::{env, mem, str};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
 use rustc_middle::middle::dependency_format::Linkage;
+use rustc_middle::middle::exported_symbols;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
@@ -659,8 +660,6 @@ impl<'a> Linker for GccLinker<'a> {
             return;
         }
 
-        // FIXME(#99978) hide #[no_mangle] symbols for proc-macros
-
         let is_windows = self.sess.target.is_like_windows;
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
@@ -1679,8 +1678,15 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
         return exports.iter().map(ToString::to_string).collect();
     }
 
-    let mut symbols = Vec::new();
+    if let CrateType::ProcMacro = crate_type {
+        exported_symbols_for_proc_macro_crate(tcx)
+    } else {
+        exported_symbols_for_non_proc_macro(tcx, crate_type)
+    }
+}
 
+fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+    let mut symbols = Vec::new();
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
         if info.level.is_below_threshold(export_threshold) {
@@ -1691,6 +1697,19 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
     symbols
 }
 
+fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
+    // `exported_symbols` will be empty when !should_codegen.
+    if !tcx.sess.opts.output_types.should_codegen() {
+        return Vec::new();
+    }
+
+    let stable_crate_id = tcx.sess.local_stable_crate_id();
+    let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
+    let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
+
+    vec![proc_macro_decls_name, metadata_symbol_name]
+}
+
 pub(crate) fn linked_symbols(
     tcx: TyCtxt<'_>,
     crate_type: CrateType,
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 34b7e09576a..22e22c833ac 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -155,8 +155,6 @@ lint_builtin_unused_doc_comment = unused doc comment
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
-lint_cast_ref_to_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
-
 lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
 
 lint_check_name_unknown = unknown lint: `{$lint_name}`
@@ -264,8 +262,6 @@ lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
 lint_improper_ctypes_char_reason = the `char` type has no C equivalent
 lint_improper_ctypes_dyn = trait objects have no C equivalent
 
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
-
 lint_improper_ctypes_enum_repr_help =
     consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 
@@ -319,6 +315,8 @@ lint_invalid_nan_comparisons_eq_ne = incorrect NaN comparison, NaN cannot be dir
 
 lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not orderable
 
+lint_invalid_reference_casting = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
+
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5e3f057d428..602071a55e5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -50,7 +50,6 @@ extern crate tracing;
 
 mod array_into_iter;
 pub mod builtin;
-mod cast_ref_to_mut;
 mod context;
 mod deref_into_dyn_supertrait;
 mod drop_forget_useless;
@@ -77,6 +76,7 @@ mod opaque_hidden_inferred_bound;
 mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
+mod reference_casting;
 mod traits;
 mod types;
 mod unused;
@@ -98,7 +98,6 @@ use rustc_span::Span;
 
 use array_into_iter::ArrayIntoIter;
 use builtin::*;
-use cast_ref_to_mut::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -117,6 +116,7 @@ use noop_method_call::*;
 use opaque_hidden_inferred_bound::*;
 use pass_by_value::*;
 use redundant_semicolon::*;
+use reference_casting::*;
 use traits::*;
 use types::*;
 use unused::*;
@@ -216,7 +216,7 @@ late_lint_methods!(
             BoxPointers: BoxPointers,
             PathStatements: PathStatements,
             LetUnderscore: LetUnderscore,
-            CastRefToMut: CastRefToMut,
+            InvalidReferenceCasting: InvalidReferenceCasting,
             // Depends on referenced function signatures in expressions
             UnusedResults: UnusedResults,
             NonUpperCaseGlobals: NonUpperCaseGlobals,
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 0613ef2c5e9..9260237fbee 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -737,10 +737,10 @@ pub enum InvalidFromUtf8Diag {
     },
 }
 
-// cast_ref_to_mut.rs
+// reference_casting.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_cast_ref_to_mut)]
-pub struct CastRefToMutDiag;
+#[diag(lint_invalid_reference_casting)]
+pub struct InvalidReferenceCastingDiag;
 
 // hidden_unicode_codepoints.rs
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/cast_ref_to_mut.rs b/compiler/rustc_lint/src/reference_casting.rs
index 84308d48c10..db8d7302a25 100644
--- a/compiler/rustc_lint/src/cast_ref_to_mut.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -3,15 +3,16 @@ use rustc_hir::{Expr, ExprKind, MutTy, TyKind, UnOp};
 use rustc_middle::ty;
 use rustc_span::sym;
 
-use crate::{lints::CastRefToMutDiag, LateContext, LateLintPass, LintContext};
+use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext};
 
 declare_lint! {
-    /// The `cast_ref_to_mut` lint checks for casts of `&T` to `&mut T`
+    /// The `invalid_reference_casting` lint checks for casts of `&T` to `&mut T`
     /// without using interior mutability.
     ///
     /// ### Example
     ///
     /// ```rust,compile_fail
+    /// # #![deny(invalid_reference_casting)]
     /// fn x(r: &i32) {
     ///     unsafe {
     ///         *(r as *const i32 as *mut i32) += 1;
@@ -28,14 +29,14 @@ declare_lint! {
     ///
     /// `UnsafeCell` is the only way to obtain aliasable data that is considered
     /// mutable.
-    CAST_REF_TO_MUT,
-    Deny,
+    INVALID_REFERENCE_CASTING,
+    Allow,
     "casts of `&T` to `&mut T` without interior mutability"
 }
 
-declare_lint_pass!(CastRefToMut => [CAST_REF_TO_MUT]);
+declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
 
-impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
+impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         let ExprKind::Unary(UnOp::Deref, e) = &expr.kind else { return; };
 
@@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for CastRefToMut {
 
         let e = e.peel_blocks();
         if let ty::Ref(..) = cx.typeck_results().node_type(e.hir_id).kind() {
-            cx.emit_spanned_lint(CAST_REF_TO_MUT, expr.span, CastRefToMutDiag);
+            cx.emit_spanned_lint(INVALID_REFERENCE_CASTING, expr.span, InvalidReferenceCastingDiag);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 2509d493a4c..ed4fb98605c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -963,12 +963,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> FfiResult<'tcx> {
         let field_ty = field.ty(self.cx.tcx, substs);
-        if field_ty.has_opaque_types() {
-            self.check_type_for_ffi(cache, field_ty)
-        } else {
-            let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
-            self.check_type_for_ffi(cache, field_ty)
-        }
+        let field_ty = self
+            .cx
+            .tcx
+            .try_normalize_erasing_regions(self.cx.param_env, field_ty)
+            .unwrap_or(field_ty);
+        self.check_type_for_ffi(cache, field_ty)
     }
 
     /// Checks if the given `VariantDef`'s field types are "ffi-safe".
@@ -982,39 +982,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     ) -> FfiResult<'tcx> {
         use FfiResult::*;
 
-        let transparent_safety = def.repr().transparent().then(|| {
-            // Can assume that at most one field is not a ZST, so only check
-            // that field's type for FFI-safety.
+        let transparent_with_all_zst_fields = if def.repr().transparent() {
             if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
-                return self.check_field_type_for_ffi(cache, field, substs);
+                // Transparent newtypes have at most one non-ZST field which needs to be checked..
+                match self.check_field_type_for_ffi(cache, field, substs) {
+                    FfiUnsafe { ty, .. } if ty.is_unit() => (),
+                    r => return r,
+                }
+
+                false
             } else {
-                // All fields are ZSTs; this means that the type should behave
-                // like (), which is FFI-unsafe... except if all fields are PhantomData,
-                // which is tested for below
-                FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+                // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
+                // `PhantomData`).
+                true
             }
-        });
-        // We can't completely trust repr(C) markings; make sure the fields are
-        // actually safe.
+        } else {
+            false
+        };
+
+        // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
         let mut all_phantom = !variant.fields.is_empty();
         for field in &variant.fields {
-            match self.check_field_type_for_ffi(cache, &field, substs) {
-                FfiSafe => {
-                    all_phantom = false;
-                }
-                FfiPhantom(..) if !def.repr().transparent() && def.is_enum() => {
-                    return FfiUnsafe {
-                        ty,
-                        reason: fluent::lint_improper_ctypes_enum_phantomdata,
-                        help: None,
-                    };
-                }
-                FfiPhantom(..) => {}
-                r => return transparent_safety.unwrap_or(r),
+            all_phantom &= match self.check_field_type_for_ffi(cache, &field, substs) {
+                FfiSafe => false,
+                // `()` fields are FFI-safe!
+                FfiUnsafe { ty, .. } if ty.is_unit() => false,
+                FfiPhantom(..) => true,
+                r @ FfiUnsafe { .. } => return r,
             }
         }
 
-        if all_phantom { FfiPhantom(ty) } else { transparent_safety.unwrap_or(FfiSafe) }
+        if all_phantom {
+            FfiPhantom(ty)
+        } else if transparent_with_all_zst_fields {
+            FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
+        } else {
+            FfiSafe
+        }
     }
 
     /// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1217,25 +1221,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
 
                 let sig = tcx.erase_late_bound_regions(sig);
-                if !sig.output().is_unit() {
-                    let r = self.check_type_for_ffi(cache, sig.output());
-                    match r {
-                        FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
-                    }
-                }
                 for arg in sig.inputs() {
-                    let r = self.check_type_for_ffi(cache, *arg);
-                    match r {
+                    match self.check_type_for_ffi(cache, *arg) {
                         FfiSafe => {}
-                        _ => {
-                            return r;
-                        }
+                        r => return r,
                     }
                 }
-                FfiSafe
+
+                let ret_ty = sig.output();
+                if ret_ty.is_unit() {
+                    return FfiSafe;
+                }
+
+                self.check_type_for_ffi(cache, ret_ty)
             }
 
             ty::Foreign(..) => FfiSafe,
@@ -1317,7 +1315,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         if let Some(ty) = self
             .cx
             .tcx
-            .normalize_erasing_regions(self.cx.param_env, ty)
+            .try_normalize_erasing_regions(self.cx.param_env, ty)
+            .unwrap_or(ty)
             .visit_with(&mut ProhibitOpaqueTypes)
             .break_value()
         {
@@ -1335,16 +1334,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         is_static: bool,
         is_return_type: bool,
     ) {
-        // We have to check for opaque types before `normalize_erasing_regions`,
-        // which will replace opaque types with their underlying concrete type.
         if self.check_for_opaque_ty(sp, ty) {
             // We've already emitted an error due to an opaque type.
             return;
         }
 
-        // it is only OK to use this function because extern fns cannot have
-        // any generic types right now:
-        let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+        let ty = self.cx.tcx.try_normalize_erasing_regions(self.cx.param_env, ty).unwrap_or(ty);
 
         // C doesn't really support passing arrays by value - the only way to pass an array by value
         // is through a struct. So, first test that the top level isn't an array, and then
@@ -1354,7 +1349,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         // Don't report FFI errors for unit return types. This check exists here, and not in
-        // `check_foreign_fn` (where it would make more sense) so that normalization has definitely
+        // the caller (where it would make more sense) so that normalization has definitely
         // happened.
         if is_return_type && ty.is_unit() {
             return;
@@ -1370,9 +1365,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     None,
                 );
             }
-            // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
-            // argument, which after substitution, is `()`, then this branch can be hit.
-            FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
             FfiResult::FfiUnsafe { ty, reason, help } => {
                 self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 240beabfc1a..b6578cb259a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -440,6 +440,10 @@ impl<'tcx> Inliner<'tcx> {
             validation: Ok(()),
         };
 
+        for var_debug_info in callee_body.var_debug_info.iter() {
+            checker.visit_var_debug_info(var_debug_info);
+        }
+
         // Traverse the MIR manually so we can account for the effects of inlining on the CFG.
         let mut work_list = vec![START_BLOCK];
         let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
@@ -847,7 +851,16 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
         if let ProjectionElem::Field(f, ty) = elem {
             let parent_ty = place_ref.ty(&self.callee_body.local_decls, self.tcx);
             let check_equal = |this: &mut Self, f_ty| {
-                if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
+                // Fast path if there is nothing to substitute.
+                if ty == f_ty {
+                    return;
+                }
+                let ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&ty));
+                let f_ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder::bind(&f_ty));
+                if ty == f_ty {
+                    return;
+                }
+                if !util::is_subtype(this.tcx, this.param_env, ty, f_ty) {
                     trace!(?ty, ?f_ty);
                     this.validation = Err("failed to normalize projection type");
                     return;