about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2021-12-02 21:32:10 -0500
committerRalf Jung <post@ralfj.de>2021-12-20 22:37:14 +0100
commit90d7dada69f92317dddc20357277bb48baa9118b (patch)
tree5bc1168fc51b40a9ddb5e42e8c5b943ecc6c0b4e
parentb5c7530fcf879576f43d31b635e8363fd8609405 (diff)
downloadrust-90d7dada69f92317dddc20357277bb48baa9118b.tar.gz
rust-90d7dada69f92317dddc20357277bb48baa9118b.zip
also compare ArgAttributes
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs67
1 files changed, 38 insertions, 29 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index a5907a2cacc..27f6a75ebe8 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -8,7 +8,7 @@ use rustc_middle::{
     ty::{self, Ty},
 };
 use rustc_target::abi;
-use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode};
 use rustc_target::spec::abi::Abi;
 
 use super::{
@@ -199,41 +199,50 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         };
         // Padding must be fully equal.
-        let pad_compat = || {
-            if caller_abi.pad != callee_abi.pad {
-                trace!(
-                    "check_argument_compat: incompatible pad: {:?} != {:?}",
-                    caller_abi.pad,
-                    callee_abi.pad
-                );
+        let pad_compat = || caller_abi.pad == callee_abi.pad;
+        // When comparing the PassMode, we have to be smart about comparing the attributes.
+        let arg_attr_compat = |a1: ArgAttributes, a2: ArgAttributes| {
+            // There's only one regular attribute that matters for the call ABI: InReg.
+            // Everything else is things like noalias, dereferencable, nonnull, ...
+            // (This also applies to pointee_size, pointee_align.)
+            if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg)
+            {
+                return false;
+            }
+            // We also compare the sign extension mode -- this could let the callee make assumptions
+            // about bits that conceptually were not even passed.
+            if a1.arg_ext != a2.arg_ext {
                 return false;
             }
             return true;
         };
-        // For comparing the PassMode, we allow the attributes to differ
-        // (e.g., it is okay for NonNull to differ between caller and callee).
-        // FIXME: Are there attributes (`call::ArgAttributes`) that do need to be checked?
-        let mode_compat = || {
-            match (caller_abi.mode, callee_abi.mode) {
-                (PassMode::Ignore, PassMode::Ignore) => return true,
-                (PassMode::Direct(_), PassMode::Direct(_)) => return true,
-                (PassMode::Pair(_, _), PassMode::Pair(_, _)) => return true,
-                (PassMode::Cast(c1), PassMode::Cast(c2)) if c1 == c2 => return true,
-                (
-                    PassMode::Indirect { attrs: _, extra_attrs: e1, on_stack: s1 },
-                    PassMode::Indirect { attrs: _, extra_attrs: e2, on_stack: s2 },
-                ) if e1.is_some() == e2.is_some() && s1 == s2 => return true,
-                _ => {}
+        let mode_compat = || match (caller_abi.mode, callee_abi.mode) {
+            (PassMode::Ignore, PassMode::Ignore) => true,
+            (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2),
+            (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => {
+                arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2)
             }
-            trace!(
-                "check_argument_compat: incompatible modes:\ncaller: {:?}\ncallee: {:?}",
-                caller_abi.mode,
-                callee_abi.mode
-            );
-            return false;
+            (PassMode::Cast(c1), PassMode::Cast(c2)) => c1 == c2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 },
+            ) => arg_attr_compat(a1, a2) && s1 == s2,
+            (
+                PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 },
+                PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 },
+            ) => arg_attr_compat(a1, a2) && arg_attr_compat(e1, e2) && s1 == s2,
+            _ => false,
         };
 
-        layout_compat() && pad_compat() && mode_compat()
+        if layout_compat() && pad_compat() && mode_compat() {
+            return true;
+        }
+        trace!(
+            "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}",
+            caller_abi,
+            callee_abi
+        );
+        return false;
     }
 
     /// Initialize a single callee argument, checking the types for compatibility.