about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-04-24 12:06:16 +0000
committerbors <bors@rust-lang.org>2025-04-24 12:06:16 +0000
commit3c877f6a477380ed61155d3bf816df09c9e05b9e (patch)
treec8a69687f1534c8512156517f90a94f2e02977c5 /compiler
parentdc8fe1f81c6cf13c0987944c525b2aa81625b5d0 (diff)
parentf45d2bd8ee55a8970093d9c3cbf7e456c926e8f6 (diff)
downloadrust-3c877f6a477380ed61155d3bf816df09c9e05b9e.tar.gz
rust-3c877f6a477380ed61155d3bf816df09c9e05b9e.zip
Auto merge of #140245 - matthiaskrgr:rollup-e0fwsfv, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #139261 (mitigate MSVC alignment issue on x86-32)
 - #140075 (Mention average in midpoint documentations)
 - #140184 (Update doc of cygwin target)
 - #140186 (Rename `compute_x` methods)
 - #140194 (minicore: Have `//@ add-core-stubs` also imply `-Cforce-unwind-tables=yes`)
 - #140195 (triagebot: label minicore changes w/ `A-test-infra-minicore` and ping jieyouxu on changes)
 - #140214 (Remove comment about handling non-global where bounds with corresponding projection)
 - #140228 (Revert overzealous parse recovery for single colons in paths)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs32
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs12
-rw-r--r--compiler/rustc_parse/src/parser/item.rs11
-rw-r--r--compiler/rustc_parse/src/parser/path.rs20
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs79
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs3
10 files changed, 121 insertions, 64 deletions
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 27f7f95f100..04c8118b616 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -594,6 +594,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     fn load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
         unsafe {
             let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
+            let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
             llvm::LLVMSetAlignment(load, align.bytes() as c_uint);
             load
         }
@@ -807,6 +808,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         assert_eq!(self.cx.type_kind(self.cx.val_ty(ptr)), TypeKind::Pointer);
         unsafe {
             let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
+            let align = align.min(self.cx().tcx.sess.target.max_reliable_alignment());
             let align =
                 if flags.contains(MemFlags::UNALIGNED) { 1 } else { align.bytes() as c_uint };
             llvm::LLVMSetAlignment(store, align);
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index b70cca14840..5115583f37c 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -1,3 +1,4 @@
+use rustc_abi::Align;
 use rustc_index::IndexVec;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::PlaceContext;
@@ -11,10 +12,6 @@ pub(super) struct CheckAlignment;
 
 impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
     fn is_enabled(&self, sess: &Session) -> bool {
-        // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
-        if sess.target.llvm_target == "i686-pc-windows-msvc" {
-            return false;
-        }
         sess.ub_checks()
     }
 
@@ -87,6 +84,33 @@ fn insert_alignment_check<'tcx>(
         ))),
     });
 
+    // If this target does not have reliable alignment, further limit the mask by anding it with
+    // the mask for the highest reliable alignment.
+    #[allow(irrefutable_let_patterns)]
+    if let max_align = tcx.sess.target.max_reliable_alignment()
+        && max_align < Align::MAX
+    {
+        let max_mask = max_align.bytes() - 1;
+        let max_mask = Operand::Constant(Box::new(ConstOperand {
+            span: source_info.span,
+            user_ty: None,
+            const_: Const::Val(
+                ConstValue::Scalar(Scalar::from_target_usize(max_mask, &tcx)),
+                tcx.types.usize,
+            ),
+        }));
+        stmts.push(Statement {
+            source_info,
+            kind: StatementKind::Assign(Box::new((
+                alignment_mask,
+                Rvalue::BinaryOp(
+                    BinOp::BitAnd,
+                    Box::new((Operand::Copy(alignment_mask), max_mask)),
+                ),
+            ))),
+        });
+    }
+
     // BitAnd the alignment mask with the pointer
     let alignment_bits =
         local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 827853be280..3404c47bba2 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -1308,18 +1308,6 @@ where
                     return true;
                 }
 
-                // We don't consider a trait-bound global if it has a projection bound.
-                //
-                // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs
-                // for an example where this is necessary.
-                for p in goal.param_env.caller_bounds().iter() {
-                    if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() {
-                        if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref {
-                            return true;
-                        }
-                    }
-                }
-
                 false
             }
             _ => false,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 39251f1ce27..4be8a90368d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2058,6 +2058,17 @@ impl<'a> Parser<'a> {
         }
         self.expect_field_ty_separator()?;
         let ty = self.parse_ty()?;
+        if self.token == token::Colon && self.look_ahead(1, |&t| t != token::Colon) {
+            self.dcx()
+                .struct_span_err(self.token.span, "found single colon in a struct field type path")
+                .with_span_suggestion_verbose(
+                    self.token.span,
+                    "write a path separator here",
+                    "::",
+                    Applicability::MaybeIncorrect,
+                )
+                .emit();
+        }
         let default = if self.token == token::Eq {
             self.bump();
             let const_expr = self.parse_expr_anon_const()?;
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 1a02d45f0e3..1093e4f4af0 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -248,19 +248,13 @@ impl<'a> Parser<'a> {
             segments.push(segment);
 
             if self.is_import_coupler() || !self.eat_path_sep() {
-                let ok_for_recovery = self.may_recover()
-                    && match style {
-                        PathStyle::Expr => true,
-                        PathStyle::Type if let Some((ident, _)) = self.prev_token.ident() => {
-                            self.token == token::Colon
-                                && ident.as_str().chars().all(|c| c.is_lowercase())
-                                && self.token.span.lo() == self.prev_token.span.hi()
-                                && self
-                                    .look_ahead(1, |token| self.token.span.hi() == token.span.lo())
-                        }
-                        _ => false,
-                    };
-                if ok_for_recovery
+                // IMPORTANT: We can *only ever* treat single colons as typo'ed double colons in
+                // expression contexts (!) since only there paths cannot possibly be followed by
+                // a colon and still form a syntactically valid construct. In pattern contexts,
+                // a path may be followed by a type annotation. E.g., `let pat:ty`. In type
+                // contexts, a path may be followed by a list of bounds. E.g., `where ty:bound`.
+                if self.may_recover()
+                    && style == PathStyle::Expr // (!)
                     && self.token == token::Colon
                     && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
                 {
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 7ecc46cc69d..ae366e29e32 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -144,6 +144,7 @@ pub struct ArgAttributes {
     /// (corresponding to LLVM's dereferenceable_or_null attributes, i.e., it is okay for this to be
     /// set on a null pointer, but all non-null pointers must be dereferenceable).
     pub pointee_size: Size,
+    /// The minimum alignment of the pointee, if any.
     pub pointee_align: Option<Align>,
 }
 
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 3c769dad630..37ea0d6e7b5 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -42,7 +42,9 @@ use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
 
-use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors};
+use rustc_abi::{
+    Align, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors,
+};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_fs_util::try_canonicalize;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
@@ -3599,6 +3601,25 @@ impl Target {
             _ => return None,
         })
     }
+
+    /// Returns whether this target is known to have unreliable alignment:
+    /// native C code for the target fails to align some data to the degree
+    /// required by the C standard. We can't *really* do anything about that
+    /// since unsafe Rust code may assume alignment any time, but we can at least
+    /// inhibit some optimizations, and we suppress the alignment checks that
+    /// would detect this unsoundness.
+    ///
+    /// Every target that returns less than `Align::MAX` here is still has a soundness bug.
+    pub fn max_reliable_alignment(&self) -> Align {
+        // FIXME(#112480) MSVC on x86-32 is unsound and fails to properly align many types with
+        // more-than-4-byte-alignment on the stack. This makes alignments larger than 4 generally
+        // unreliable on 32bit Windows.
+        if self.is_like_windows && self.arch == "x86" {
+            Align::from_bytes(4).unwrap()
+        } else {
+            Align::MAX
+        }
+    }
 }
 
 /// Either a target tuple string or a path to a JSON file.
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index cf6d2bc151f..00101010f14 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -240,8 +240,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
                 continue;
             }
-            // FIXME(oli-obk): it is suspicious that we are dropping the constness and
-            // polarity here.
             let wc = self.where_clause_may_apply(stack, bound_trait_ref)?;
             if wc.may_apply() {
                 candidates.vec.push(ParamCandidate(bound));
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 54b6c22b2d8..cad7e42fd82 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -1,3 +1,8 @@
+//! Core logic responsible for determining what it means for various type system
+//! primitives to be "well formed". Actually checking whether these primitives are
+//! well formed is performed elsewhere (e.g. during type checking or item well formedness
+//! checking).
+
 use std::iter;
 
 use rustc_hir as hir;
@@ -15,12 +20,13 @@ use tracing::{debug, instrument, trace};
 
 use crate::infer::InferCtxt;
 use crate::traits;
+
 /// Returns the set of obligations needed to make `arg` well-formed.
 /// If `arg` contains unresolved inference variables, this may include
 /// further WF obligations. However, if `arg` IS an unresolved
 /// inference variable, returns `None`, because we are not able to
-/// make any progress at all. This is to prevent "livelock" where we
-/// say "$0 is WF if $0 is WF".
+/// make any progress at all. This is to prevent cycles where we
+/// say "?0 is WF if ?0 is WF".
 pub fn obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -29,14 +35,14 @@ pub fn obligations<'tcx>(
     arg: GenericArg<'tcx>,
     span: Span,
 ) -> Option<PredicateObligations<'tcx>> {
-    // Handle the "livelock" case (see comment above) by bailing out if necessary.
+    // Handle the "cycle" case (see comment above) by bailing out if necessary.
     let arg = match arg.unpack() {
         GenericArgKind::Type(ty) => {
             match ty.kind() {
                 ty::Infer(ty::TyVar(_)) => {
                     let resolved_ty = infcx.shallow_resolve(ty);
                     if resolved_ty == ty {
-                        // No progress, bail out to prevent "livelock".
+                        // No progress, bail out to prevent cycles.
                         return None;
                     } else {
                         resolved_ty
@@ -51,7 +57,7 @@ pub fn obligations<'tcx>(
                 ty::ConstKind::Infer(_) => {
                     let resolved = infcx.shallow_resolve_const(ct);
                     if resolved == ct {
-                        // No progress.
+                        // No progress, bail out to prevent cycles.
                         return None;
                     } else {
                         resolved
@@ -74,7 +80,7 @@ pub fn obligations<'tcx>(
         recursion_depth,
         item: None,
     };
-    wf.compute(arg);
+    wf.add_wf_preds_for_generic_arg(arg);
     debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
 
     let result = wf.normalize(infcx);
@@ -97,7 +103,7 @@ pub fn unnormalized_obligations<'tcx>(
 
     // However, if `arg` IS an unresolved inference variable, returns `None`,
     // because we are not able to make any progress at all. This is to prevent
-    // "livelock" where we say "$0 is WF if $0 is WF".
+    // cycles where we say "?0 is WF if ?0 is WF".
     if arg.is_non_region_infer() {
         return None;
     }
@@ -115,7 +121,7 @@ pub fn unnormalized_obligations<'tcx>(
         recursion_depth: 0,
         item: None,
     };
-    wf.compute(arg);
+    wf.add_wf_preds_for_generic_arg(arg);
     Some(wf.out)
 }
 
@@ -140,7 +146,7 @@ pub fn trait_obligations<'tcx>(
         recursion_depth: 0,
         item: Some(item),
     };
-    wf.compute_trait_pred(trait_pred, Elaborate::All);
+    wf.add_wf_preds_for_trait_pred(trait_pred, Elaborate::All);
     debug!(obligations = ?wf.out);
     wf.normalize(infcx)
 }
@@ -171,7 +177,7 @@ pub fn clause_obligations<'tcx>(
     // It's ok to skip the binder here because wf code is prepared for it
     match clause.kind().skip_binder() {
         ty::ClauseKind::Trait(t) => {
-            wf.compute_trait_pred(t, Elaborate::None);
+            wf.add_wf_preds_for_trait_pred(t, Elaborate::None);
         }
         ty::ClauseKind::HostEffect(..) => {
             // Technically the well-formedness of this predicate is implied by
@@ -179,22 +185,22 @@ pub fn clause_obligations<'tcx>(
         }
         ty::ClauseKind::RegionOutlives(..) => {}
         ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
-            wf.compute(ty.into());
+            wf.add_wf_preds_for_generic_arg(ty.into());
         }
         ty::ClauseKind::Projection(t) => {
-            wf.compute_alias_term(t.projection_term);
-            wf.compute(t.term.into_arg());
+            wf.add_wf_preds_for_alias_term(t.projection_term);
+            wf.add_wf_preds_for_generic_arg(t.term.into_arg());
         }
         ty::ClauseKind::ConstArgHasType(ct, ty) => {
-            wf.compute(ct.into());
-            wf.compute(ty.into());
+            wf.add_wf_preds_for_generic_arg(ct.into());
+            wf.add_wf_preds_for_generic_arg(ty.into());
         }
         ty::ClauseKind::WellFormed(arg) => {
-            wf.compute(arg);
+            wf.add_wf_preds_for_generic_arg(arg);
         }
 
         ty::ClauseKind::ConstEvaluatable(ct) => {
-            wf.compute(ct.into());
+            wf.add_wf_preds_for_generic_arg(ct.into());
         }
     }
 
@@ -372,14 +378,18 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     }
 
     /// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
-    fn compute_trait_pred(&mut self, trait_pred: ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
+    fn add_wf_preds_for_trait_pred(
+        &mut self,
+        trait_pred: ty::TraitPredicate<'tcx>,
+        elaborate: Elaborate,
+    ) {
         let tcx = self.tcx();
         let trait_ref = trait_pred.trait_ref;
 
         // Negative trait predicates don't require supertraits to hold, just
         // that their args are WF.
         if trait_pred.polarity == ty::PredicatePolarity::Negative {
-            self.compute_negative_trait_pred(trait_ref);
+            self.add_wf_preds_for_negative_trait_pred(trait_ref);
             return;
         }
 
@@ -445,15 +455,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
     // Compute the obligations that are required for `trait_ref` to be WF,
     // given that it is a *negative* trait predicate.
-    fn compute_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
+    fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
         for arg in trait_ref.args {
-            self.compute(arg);
+            self.add_wf_preds_for_generic_arg(arg);
         }
     }
 
     /// Pushes the obligations required for an alias (except inherent) to be WF
     /// into `self.out`.
-    fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
+    fn add_wf_preds_for_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
         // A projection is well-formed if
         //
         // (a) its predicates hold (*)
@@ -478,13 +488,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         let obligations = self.nominal_obligations(data.def_id, data.args);
         self.out.extend(obligations);
 
-        self.compute_projection_args(data.args);
+        self.add_wf_preds_for_projection_args(data.args);
     }
 
     /// Pushes the obligations required for an inherent alias to be WF
     /// into `self.out`.
     // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`.
-    fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
+    fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
         // An inherent projection is well-formed if
         //
         // (a) its predicates hold (*)
@@ -511,7 +521,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         data.args.visit_with(self);
     }
 
-    fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
+    fn add_wf_preds_for_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
         let tcx = self.tcx();
         let cause = self.cause(ObligationCauseCode::WellFormed(None));
         let param_env = self.param_env;
@@ -557,7 +567,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
     /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
     #[instrument(level = "debug", skip(self))]
-    fn compute(&mut self, arg: GenericArg<'tcx>) {
+    fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) {
         arg.visit_with(self);
         debug!(?self.out);
     }
@@ -596,7 +606,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
             .collect()
     }
 
-    fn from_object_ty(
+    fn add_wf_preds_for_dyn_ty(
         &mut self,
         ty: Ty<'tcx>,
         data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -651,6 +661,13 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     outlives,
                 ));
             }
+
+            // We don't add any wf predicates corresponding to the trait ref's generic arguments
+            // which allows code like this to compile:
+            // ```rust
+            // trait Trait<T: Sized> {}
+            // fn foo(_: &dyn Trait<[u32]>) {}
+            // ```
         }
     }
 }
@@ -761,7 +778,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 self.out.extend(obligations);
             }
             ty::Alias(ty::Inherent, data) => {
-                self.compute_inherent_projection(data);
+                self.add_wf_preds_for_inherent_projection(data);
                 return; // Subtree handled by compute_inherent_projection.
             }
 
@@ -895,7 +912,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 //
                 // Here, we defer WF checking due to higher-ranked
                 // regions. This is perhaps not ideal.
-                self.from_object_ty(t, data, r);
+                self.add_wf_preds_for_dyn_ty(t, data, r);
 
                 // FIXME(#27579) RFC also considers adding trait
                 // obligations that don't refer to Self and
@@ -917,11 +934,11 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
             // 1. Check if they have been resolved, and if so proceed with
             //    THAT type.
             // 2. If not, we've at least simplified things (e.g., we went
-            //    from `Vec<$0>: WF` to `$0: WF`), so we can
+            //    from `Vec?0>: WF` to `?0: WF`), so we can
             //    register a pending obligation and keep
             //    moving. (Goal is that an "inductive hypothesis"
             //    is satisfied to ensure termination.)
-            // See also the comment on `fn obligations`, describing "livelock"
+            // See also the comment on `fn obligations`, describing cycle
             // prevention, which happens before this can be reached.
             ty::Infer(_) => {
                 let cause = self.cause(ObligationCauseCode::WellFormed(None));
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 3d4ab33240a..63ea035bd0e 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -347,7 +347,8 @@ fn adjust_for_rust_scalar<'tcx>(
             None
         };
         if let Some(kind) = kind {
-            attrs.pointee_align = Some(pointee.align);
+            attrs.pointee_align =
+                Some(pointee.align.min(cx.tcx().sess.target.max_reliable_alignment()));
 
             // `Box` are not necessarily dereferenceable for the entire duration of the function as
             // they can be deallocated at any time. Same for non-frozen shared references (see