about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-06-08 20:38:43 +0200
committerFabian Wolff <fabian.wolff@alumni.ethz.ch>2021-06-08 20:41:16 +0200
commit7b2befc27b2e65e0ffdd9e8280951e7349317e39 (patch)
treee7da0467d4ddff4056842a309e83b65f9e612a58
parenta50d72158e08e02cfc051b863017bdbd2c45b637 (diff)
downloadrust-7b2befc27b2e65e0ffdd9e8280951e7349317e39.tar.gz
rust-7b2befc27b2e65e0ffdd9e8280951e7349317e39.zip
Check the number of generic lifetime and const parameters of intrinsics
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0094.md3
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs86
-rw-r--r--compiler/rustc_typeck/src/errors.rs8
-rw-r--r--src/test/ui/simd-intrinsic/issue-85855.rs20
-rw-r--r--src/test/ui/simd-intrinsic/issue-85855.stderr27
5 files changed, 116 insertions, 28 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md
index 42baa65bf9f..42cd2aa1853 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0094.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0094.md
@@ -1,4 +1,5 @@
-An invalid number of type parameters was given to an intrinsic function.
+An invalid number of generic type, lifetime, or const parameters was
+given to an intrinsic function.
 
 Erroneous code example:
 
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 5741b6824b5..7a7ecb06132 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -3,11 +3,11 @@
 
 use crate::errors::{
     SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
-    WrongNumberOfTypeArgumentsToInstrinsic,
+    WrongNumberOfGenericArgumentsToInstrinsic,
 };
 use crate::require_same_types;
 
-use rustc_errors::struct_span_err;
+use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::subst::Subst;
@@ -21,36 +21,68 @@ fn equate_intrinsic_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     it: &hir::ForeignItem<'_>,
     n_tps: usize,
+    n_lts: usize,
     sig: ty::PolyFnSig<'tcx>,
 ) {
-    match it.kind {
-        hir::ForeignItemKind::Fn(..) => {}
+    let (gen_lts, gen_tys, gen_cns, span) = match &it.kind {
+        hir::ForeignItemKind::Fn(.., generics) => {
+            let mut gen_lts = 0;
+            let mut gen_tys = 0;
+            let mut gen_cns = 0;
+
+            for param in generics.params {
+                match param.kind {
+                    hir::GenericParamKind::Lifetime { .. } => {
+                        gen_lts += 1;
+                    }
+                    hir::GenericParamKind::Type { .. } => {
+                        gen_tys += 1;
+                    }
+                    hir::GenericParamKind::Const { .. } => {
+                        gen_cns += 1;
+                    }
+                }
+            }
+
+            (gen_lts, gen_tys, gen_cns, generics.span)
+        }
         _ => {
             struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function")
                 .span_label(it.span, "expected a function")
                 .emit();
             return;
         }
-    }
-
-    let i_n_tps = tcx.generics_of(it.def_id).own_counts().types;
-    if i_n_tps != n_tps {
-        let span = match it.kind {
-            hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span,
-            _ => bug!(),
-        };
+    };
 
-        tcx.sess.emit_err(WrongNumberOfTypeArgumentsToInstrinsic {
+    if gen_lts != n_lts {
+        tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic {
+            span,
+            found: gen_lts,
+            expected: n_lts,
+            expected_pluralize: pluralize!(n_lts),
+            descr: "lifetime",
+        });
+    } else if gen_tys != n_tps {
+        tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic {
             span,
-            found: i_n_tps,
+            found: gen_tys,
             expected: n_tps,
+            expected_pluralize: pluralize!(n_tps),
+            descr: "type",
         });
-        return;
+    } else if gen_cns != 0 {
+        tcx.sess.emit_err(WrongNumberOfGenericArgumentsToInstrinsic {
+            span,
+            found: gen_cns,
+            expected: 0,
+            expected_pluralize: pluralize!(0),
+            descr: "const",
+        });
+    } else {
+        let fty = tcx.mk_fn_ptr(sig);
+        let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
+        require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
     }
-
-    let fty = tcx.mk_fn_ptr(sig);
-    let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
-    require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
 }
 
 /// Returns `true` if the given intrinsic is unsafe to call or not.
@@ -121,7 +153,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
         })
     };
 
-    let (n_tps, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+    let (n_tps, n_lts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
         let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
@@ -143,7 +175,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 return;
             }
         };
-        (n_tps, inputs, output, hir::Unsafety::Unsafe)
+        (n_tps, 0, inputs, output, hir::Unsafety::Unsafe)
     } else {
         let unsafety = intrinsic_operation_unsafety(intrinsic_name);
         let (n_tps, inputs, output) = match intrinsic_name {
@@ -372,11 +404,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                 return;
             }
         };
-        (n_tps, inputs, output, unsafety)
+        (
+            n_tps,
+            if matches!(intrinsic_name, sym::va_copy) { 1 } else { 0 },
+            inputs,
+            output,
+            unsafety,
+        )
     };
     let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
-    equate_intrinsic_type(tcx, it, n_tps, sig)
+    equate_intrinsic_type(tcx, it, n_tps, n_lts, sig)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -472,5 +510,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         Abi::PlatformIntrinsic,
     );
     let sig = ty::Binder::dummy(sig);
-    equate_intrinsic_type(tcx, it, n_tps, sig)
+    equate_intrinsic_type(tcx, it, n_tps, 0, sig)
 }
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 5068242692a..bc686a025a6 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -24,13 +24,15 @@ pub struct UnrecognizedAtomicOperation<'a> {
 
 #[derive(SessionDiagnostic)]
 #[error = "E0094"]
-pub struct WrongNumberOfTypeArgumentsToInstrinsic {
-    #[message = "intrinsic has wrong number of type \
+pub struct WrongNumberOfGenericArgumentsToInstrinsic<'a> {
+    #[message = "intrinsic has wrong number of {descr} \
                          parameters: found {found}, expected {expected}"]
-    #[label = "expected {expected} type parameter"]
+    #[label = "expected {expected} {descr} parameter{expected_pluralize}"]
     pub span: Span,
     pub found: usize,
     pub expected: usize,
+    pub expected_pluralize: &'a str,
+    pub descr: &'a str,
 }
 
 #[derive(SessionDiagnostic)]
diff --git a/src/test/ui/simd-intrinsic/issue-85855.rs b/src/test/ui/simd-intrinsic/issue-85855.rs
new file mode 100644
index 00000000000..61aa15be47f
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/issue-85855.rs
@@ -0,0 +1,20 @@
+// Check that appropriate errors are reported if an intrinsic is defined
+// with the wrong number of generic lifetime/type/const parameters, and
+// that no ICE occurs in these cases.
+
+#![feature(platform_intrinsics)]
+#![crate_type="lib"]
+
+extern "platform-intrinsic" {
+    fn simd_saturating_add<'a, T: 'a>(x: T, y: T);
+    //~^ ERROR: intrinsic has wrong number of lifetime parameters
+
+    fn simd_add<'a, T>(x: T, y: T);
+    //~^ ERROR: intrinsic has wrong number of lifetime parameters
+
+    fn simd_sub<T, U>(x: T, y: U);
+    //~^ ERROR: intrinsic has wrong number of type parameters
+
+    fn simd_mul<T, const N: usize>(x: T, y: T);
+    //~^ ERROR: intrinsic has wrong number of const parameters
+}
diff --git a/src/test/ui/simd-intrinsic/issue-85855.stderr b/src/test/ui/simd-intrinsic/issue-85855.stderr
new file mode 100644
index 00000000000..7dfdecb9520
--- /dev/null
+++ b/src/test/ui/simd-intrinsic/issue-85855.stderr
@@ -0,0 +1,27 @@
+error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0
+  --> $DIR/issue-85855.rs:9:27
+   |
+LL |     fn simd_saturating_add<'a, T: 'a>(x: T, y: T);
+   |                           ^^^^^^^^^^^ expected 0 lifetime parameters
+
+error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0
+  --> $DIR/issue-85855.rs:12:16
+   |
+LL |     fn simd_add<'a, T>(x: T, y: T);
+   |                ^^^^^^^ expected 0 lifetime parameters
+
+error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1
+  --> $DIR/issue-85855.rs:15:16
+   |
+LL |     fn simd_sub<T, U>(x: T, y: U);
+   |                ^^^^^^ expected 1 type parameter
+
+error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0
+  --> $DIR/issue-85855.rs:18:16
+   |
+LL |     fn simd_mul<T, const N: usize>(x: T, y: T);
+   |                ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0094`.