From: Enes Cevik <[email protected]>

This patch adds a validation mechanism to the typechecker. This mechanism
verifies intrinsic declarations against predefined signature rules. If
a signature is incorrect, the compiler emits the proper diagnostic and
prevents the malformed intrinsic from reaching the backend.

gcc/rust/ChangeLog:

        * Make-lang.in: Add rust-hir-type-check-intrinsic.o.
        * typecheck/rust-hir-type-check-implitem.cc
        (TypeCheckTopLevelExternItem::visit): Check intrinsic signature.
        * typecheck/rust-hir-type-check-intrinsic.cc: New file.
        * typecheck/rust-hir-type-check-intrinsic.h: New file.

gcc/testsuite/ChangeLog:

        * rust/compile/ctlz.rs: Fix incorrect intrinsic signature.
        * rust/compile/ctlz_nonzero.rs: Likewise.
        * rust/compile/cttz.rs: Likewise.
        * rust/compile/cttz_nonzero.rs: Likewise.
        * rust/compile/issue-4245.rs: Likewise.
        * rust/compile/torture/intrinsics-3.rs: Likewise.
        * rust/execute/torture/ctlz.rs: Likewise.
        * rust/execute/torture/ctlz_i16.rs: Likewise.
        * rust/execute/torture/ctlz_i32.rs: Likewise.
        * rust/execute/torture/ctlz_i64.rs: Likewise.
        * rust/execute/torture/ctlz_i8.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_i16.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_i32.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_i64.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_i8.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_u16.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_u32.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_u64.rs: Likewise.
        * rust/execute/torture/ctlz_nonzero_u8.rs: Likewise.
        * rust/execute/torture/ctlz_u16.rs: Likewise.
        * rust/execute/torture/ctlz_u32.rs: Likewise.
        * rust/execute/torture/ctlz_u64.rs: Likewise.
        * rust/execute/torture/ctlz_u8.rs: Likewise.
        * rust/execute/torture/cttz.rs: Likewise.
        * rust/execute/torture/cttz_nonzero.rs: Likewise.
        * rust/compile/intrinsic-checker.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/5bac1f48fab4c02255f4a5e9b439bdcd03645f52

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4587

 gcc/rust/Make-lang.in                         |   1 +
 .../typecheck/rust-hir-type-check-implitem.cc |   6 +
 .../rust-hir-type-check-intrinsic.cc          | 788 ++++++++++++++++++
 .../typecheck/rust-hir-type-check-intrinsic.h |  89 ++
 gcc/testsuite/rust/compile/ctlz.rs            |   2 +-
 gcc/testsuite/rust/compile/ctlz_nonzero.rs    |   2 +-
 gcc/testsuite/rust/compile/cttz.rs            |   2 +-
 gcc/testsuite/rust/compile/cttz_nonzero.rs    |   2 +-
 .../rust/compile/intrinsic-checker.rs         |  27 +
 gcc/testsuite/rust/compile/issue-4245.rs      |   2 +-
 .../rust/compile/torture/intrinsics-3.rs      |   4 +-
 gcc/testsuite/rust/execute/torture/ctlz.rs    |   2 +-
 .../rust/execute/torture/ctlz_i16.rs          |   2 +-
 .../rust/execute/torture/ctlz_i32.rs          |   2 +-
 .../rust/execute/torture/ctlz_i64.rs          |   2 +-
 gcc/testsuite/rust/execute/torture/ctlz_i8.rs |   2 +-
 .../rust/execute/torture/ctlz_nonzero.rs      |   2 +-
 .../rust/execute/torture/ctlz_nonzero_i16.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_i32.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_i64.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_i8.rs   |   2 +-
 .../rust/execute/torture/ctlz_nonzero_u16.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_u32.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_u64.rs  |   2 +-
 .../rust/execute/torture/ctlz_nonzero_u8.rs   |   2 +-
 .../rust/execute/torture/ctlz_u16.rs          |   2 +-
 .../rust/execute/torture/ctlz_u32.rs          |   2 +-
 .../rust/execute/torture/ctlz_u64.rs          |   2 +-
 gcc/testsuite/rust/execute/torture/ctlz_u8.rs |   2 +-
 gcc/testsuite/rust/execute/torture/cttz.rs    |   2 +-
 .../rust/execute/torture/cttz_nonzero.rs      |   2 +-
 31 files changed, 938 insertions(+), 27 deletions(-)
 create mode 100644 gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
 create mode 100644 gcc/rust/typecheck/rust-hir-type-check-intrinsic.h
 create mode 100644 gcc/testsuite/rust/compile/intrinsic-checker.rs

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 5a7da1cfe..d8093dad6 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -177,6 +177,7 @@ GRS_OBJS = \
     rust/rust-hir-type-check-stmt.o \
     rust/rust-hir-type-check-enumitem.o \
     rust/rust-hir-type-check-implitem.o \
+    rust/rust-hir-type-check-intrinsic.o \
     rust/rust-borrow-checker.o \
     rust/rust-borrow-checker-diagnostics.o\
     rust/rust-bir-builder-expr-stmt.o \
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 8e07cc5f8..850ed0758 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -21,6 +21,7 @@
 #include "rust-hir-full-decls.h"
 #include "rust-hir-pattern.h"
 #include "rust-hir-type-check-base.h"
+#include "rust-hir-type-check-intrinsic.h"
 #include "rust-hir-type-check-type.h"
 #include "rust-hir-type-check-expr.h"
 #include "rust-hir-type-check-pattern.h"
@@ -157,6 +158,11 @@ TypeCheckTopLevelExternItem::visit 
(HIR::ExternalFunctionItem &function)
     region_constraints);
 
   context->insert_type (function.get_mappings (), fnType);
+
+  if (parent.get_abi () == Rust::ABI::INTRINSIC
+      && IntrinsicChecker::check (fnType) == IntrinsicCheckResult::Invalid)
+    return;
+
   resolved = fnType;
 }
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
new file mode 100644
index 000000000..52754f202
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -0,0 +1,788 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-hir-type-check-intrinsic.h"
+#include "rust-diagnostics.h"
+#include "rust-intrinsic-values.h"
+#include "rust-system.h"
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+using IValue = Values::Intrinsics;
+using IRT = IntrinsicRuleType;
+
+const std::unordered_map<std::string, IntrinsicRules>
+  IntrinsicChecker::intrinsic_rules = {
+    // fn unreachable() -> !;
+    {IValue::UNREACHABLE, {0, {}, IRT::Never}},
+
+    // pub fn sqrtf32(x: f32) -> f32;
+    {IValue::SQRTF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn sqrtf64(x: f64) -> f64;
+    {IValue::SQRTF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn sinf32(x: f32) -> f32;
+    {IValue::SINF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn sinf64(x: f64) -> f64;
+    {IValue::SINF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn cosf32(x: f32) -> f32;
+    {IValue::COSF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn cosf64(x: f64) -> f64;
+    {IValue::COSF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn expf32(x: f32) -> f32;
+    {IValue::EXPF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn expf64(x: f64) -> f64;
+    {IValue::EXPF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn exp2f32(x: f32) -> f32;
+    {IValue::EXP2F32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn exp2f64(x: f64) -> f64;
+    {IValue::EXP2F64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn logf32(x: f32) -> f32;
+    {IValue::LOGF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn logf64(x: f64) -> f64;
+    {IValue::LOGF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn log10f32(x: f32) -> f32;
+    {IValue::LOG10F32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn log10f64(x: f64) -> f64;
+    {IValue::LOG10F64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn log2f32(x: f32) -> f32;
+    {IValue::LOG2F32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn log2f64(x: f64) -> f64;
+    {IValue::LOG2F64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn fabsf32(x: f32) -> f32;
+    {IValue::FABSF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn fabsf64(x: f64) -> f64;
+    {IValue::FABSF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn floorf32(x: f32) -> f32;
+    {IValue::FLOORF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn floorf64(x: f64) -> f64;
+    {IValue::FLOORF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn ceilf32(x: f32) -> f32;
+    {IValue::CEILF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn ceilf64(x: f64) -> f64;
+    {IValue::CEILF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn truncf32(x: f32) -> f32;
+    {IValue::TRUNCF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn truncf64(x: f64) -> f64;
+    {IValue::TRUNCF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn rintf32(x: f32) -> f32;
+    {IValue::RINTF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn rintf64(x: f64) -> f64;
+    {IValue::RINTF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn nearbyintf32(x: f32) -> f32;
+    {IValue::NEARBYINTF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn nearbyintf64(x: f64) -> f64;
+    {IValue::NEARBYINTF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn roundf32(x: f32) -> f32;
+    {IValue::ROUNDF32, {0, {IRT::F32}, IRT::F32}},
+    // pub fn roundf64(x: f64) -> f64;
+    {IValue::ROUNDF64, {0, {IRT::F64}, IRT::F64}},
+    // pub fn minnumf32(x: f32, y: f32) -> f32;
+    {IValue::MINNUMF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
+    // pub fn minnumf64(x: f64, y: f64) -> f64;
+    {IValue::MINNUMF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
+    // pub fn maxnumf32(x: f32, y: f32) -> f32;
+    {IValue::MAXNUMF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
+    // pub fn maxnumf64(x: f64, y: f64) -> f64;
+    {IValue::MAXNUMF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
+
+    // pub fn powf32(a: f32, x: f32) -> f32;
+    {IValue::POWF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
+    // pub fn powf64(a: f64, x: f64) -> f64;
+    {IValue::POWF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
+    // pub fn copysignf32(x: f32, y: f32) -> f32;
+    {IValue::COPYSIGNF32, {0, {IRT::F32, IRT::F32}, IRT::F32}},
+    // pub fn copysignf64(x: f64, y: f64) -> f64;
+    {IValue::COPYSIGNF64, {0, {IRT::F64, IRT::F64}, IRT::F64}},
+
+    // pub fn fmaf32(a: f32, b: f32, c: f32) -> f32;
+    {IValue::FMAF32, {0, {IRT::F32, IRT::F32, IRT::F32}, IRT::F32}},
+    // pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
+    {IValue::FMAF64, {0, {IRT::F64, IRT::F64, IRT::F64}, IRT::F64}},
+
+    // pub fn powif32(a: f32, x: i32) -> f32;
+    {IValue::POWIF32, {0, {IRT::F32, IRT::I32}, IRT::F32}},
+    // pub fn powif64(a: f64, x: i32) -> f64;
+    {IValue::POWIF64, {0, {IRT::F64, IRT::I32}, IRT::F64}},
+
+    // pub fn abort() -> !;
+    {IValue::ABORT, {0, {}, IRT::Never}},
+    // pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
+    {IValue::OFFSET,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
+    // pub fn size_of<T>() -> usize;
+    {IValue::SIZE_OF, {1, {}, IRT::Usize}},
+    // pub fn transmute<T, U>(e: T) -> U;
+    {IValue::TRANSMUTE, {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
+    // pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
+    {IValue::ADD_WITH_OVERFLOW,
+     {1,
+      {IRT::FirstGeneric, IRT::FirstGeneric},
+      IRT::TupleFirstGenericAndBool}},
+    // pub fn sub_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
+    {IValue::SUB_WITH_OVERFLOW,
+     {1,
+      {IRT::FirstGeneric, IRT::FirstGeneric},
+      IRT::TupleFirstGenericAndBool}},
+    // pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
+    {IValue::MUL_WITH_OVERFLOW,
+     {1,
+      {IRT::FirstGeneric, IRT::FirstGeneric},
+      IRT::TupleFirstGenericAndBool}},
+    // fn copy<T>(src: *const T, dst: *mut T, count: usize);
+    {IValue::COPY,
+     {1,
+      {IRT::ConstPtrFirstGeneric, IRT::MutPtrFirstGeneric, IRT::Usize},
+      IRT::Unit}},
+    // fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
+    {IValue::COPY_NONOVERLAPPING,
+     {1,
+      {IRT::ConstPtrFirstGeneric, IRT::MutPtrFirstGeneric, IRT::Usize},
+      IRT::Unit}},
+    // pub fn prefetch_read_data<T>(data: *const T, locality: i32);
+    {IValue::PREFETCH_READ_DATA,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::I32}, IRT::Unit}},
+    // pub fn prefetch_write_data<T>(data: *const T, locality: i32);
+    {IValue::PREFETCH_WRITE_DATA,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::I32}, IRT::Unit}},
+    // pub unsafe fn atomic_store_seqcst<T: Copy>(_dst: *mut T, _val: T);
+    {IValue::ATOMIC_STORE_SEQCST,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+    // pub unsafe fn atomic_store_release<T: Copy>(_dst: *mut T, _val: T);
+    {IValue::ATOMIC_STORE_RELEASE,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+    // pub unsafe fn atomic_store_relaxed<T: Copy>(_dst: *mut T, _val: T);
+    {IValue::ATOMIC_STORE_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+    // pub unsafe fn atomic_store_unordered<T: Copy>(_dst: *mut T, _val: T);
+    {IValue::ATOMIC_STORE_UNORDERED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+    // pub unsafe fn atomic_load_seqcst<T: Copy>(_src: *const T) -> T;
+    {IValue::ATOMIC_LOAD_SEQCST,
+     {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_load_acquire<T: Copy>(_src: *const T) -> T;
+    {IValue::ATOMIC_LOAD_ACQUIRE,
+     {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_load_relaxed<T: Copy>(_src: *const T) -> T;
+    {IValue::ATOMIC_LOAD_RELAXED,
+     {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T;
+    {IValue::ATOMIC_LOAD_UNORDERED,
+     {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_ADD,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_SUB,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_MUL,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_div<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_DIV,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_rem<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_REM,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_shl<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_SHL,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T;
+    {IValue::UNCHECKED_SHR,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn uninit<T>() -> T
+    {IValue::UNINIT, {1, {}, IRT::FirstGeneric}},
+    // pub fn move_val_init<T>(dst: *mut T, src: T);
+    {IValue::MOVE_VAL_INIT,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+    // pub fn rotate_left<T: Copy>(x: T, y: T) -> T;
+    {IValue::ROTATE_LEFT,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
+    {IValue::ROTATE_RIGHT,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn wrapping_add<T: Copy>(a: T, b: T) -> T;
+    {IValue::WRAPPING_ADD,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn wrapping_sub<T: Copy>(a: T, b: T) -> T;
+    {IValue::WRAPPING_SUB,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn wrapping_mul<T: Copy>(a: T, b: T) -> T;
+    {IValue::WRAPPING_MUL,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn saturating_add<T: Copy>(a: T, b: T) -> T;
+    {IValue::SATURATING_ADD,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn saturating_sub<T: Copy>(a: T, b: T) -> T;
+    {IValue::SATURATING_SUB,
+     {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn likely(b: bool) -> bool;
+    {IValue::LIKELY, {0, {IRT::Bool}, IRT::Bool}},
+    // pub fn unlikely(b: bool) -> bool;
+    {IValue::UNLIKELY, {0, {IRT::Bool}, IRT::Bool}},
+    // fn discriminant_value<T>(v: &T) -> <T as 
DiscriminantKind>::Discriminant;
+    {IValue::DISCRIMINANT_VALUE,
+     {1, {IRT::RefFirstGeneric}, IRT::AssocTypePlaceholder}},
+    // pub fn variant_count<T>() -> usize;
+    {IValue::VARIANT_COUNT, {1, {}, IRT::Usize}},
+    // NOTE: The return value was temporarily set to () instead of i32.
+    // pub unsafe fn catch_unwind(
+    //    _try_fn: fn(_: *mut u8),
+    //    _data: *mut u8,
+    //    _catch_fn: fn(_: *mut u8, _: *mut u8),
+    // ) -> i32
+    {IValue::CATCH_UNWIND,
+     {0,
+      {IRT::Fn_MutPtrU8, IRT::MutPtrU8, IRT::Fn_MutPtrU8MutPtrU8},
+      IRT::Unit}},
+    // pub fn r#try(
+    //                 try_fn: fn(*mut u8),
+    //                 data: *mut u8,
+    //                 catch_fn: fn(*mut u8,
+    //                 *mut u8)
+    // ) -> i32;
+    {IValue::TRY,
+     {0,
+      {IRT::Fn_MutPtrU8, IRT::MutPtrU8, IRT::Fn_MutPtrU8MutPtrU8},
+      IRT::I32}},
+    // pub fn assume(b: bool);
+    {IValue::ASSUME, {0, {IRT::Bool}, IRT::Unit}},
+    // pub fn min_align_of<T>() -> usize;
+    {IValue::MIN_ALIGN_OF, {1, {}, IRT::Usize}},
+    // pub fn needs_drop<T>() -> bool;
+    {IValue::NEEDS_DROP, {1, {}, IRT::Bool}},
+    // pub fn caller_location() -> &'static crate::panic::Location<'static>;
+    {IValue::CALLER_LOCATION, {0, {}, IRT::RefAdt}},
+    // pub fn ctpop<T: Copy>(x: T) -> T;
+    {IValue::CTPOP, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+
+    // pub fn ctlz<T: Copy>(x: T) -> T;
+    {IValue::CTLZ, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn ctlz_nonzero<T: Copy>(x: T) -> T;
+    {IValue::CTLZ_NONZERO, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn cttz<T: Copy>(x: T) -> T;
+    {IValue::CTTZ, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn cttz_nonzero<T: Copy>(x: T) -> T;
+    {IValue::CTTZ_NONZERO, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn bswap<T: Copy>(x: T) -> T;
+    {IValue::BSWAP, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn bitreverse<T: Copy>(x: T) -> T;
+    {IValue::BITREVERSE, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn type_id<T: ?Sized + 'static>() -> u64;
+    {IValue::TYPE_ID, {1, {}, IRT::U64}},
+    // pub fn ptr_guaranteed_eq<T>(ptr: *const T, other: *const T) -> bool;
+    {IValue::PTR_GUARANTEED_EQ,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::ConstPtrFirstGeneric}, IRT::Bool}},
+    // pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
+    {IValue::PTR_GUARANTEED_NE,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::ConstPtrFirstGeneric}, IRT::Bool}},
+    // pub fn rustc_peek<T>(_: T) -> T;
+    {IValue::RUSTC_PEEK, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub fn type_name<T: ?Sized>() -> &'static str;
+    {IValue::TYPE_NAME, {1, {}, IRT::RefStaticStr}},
+    // pub fn forget<T: ?Sized>(_: T);
+    {IValue::FORGET, {1, {IRT::FirstGeneric}, IRT::Unit}},
+    // pub fn black_box<T>(mut dummy: T) -> T
+    {IValue::BLACK_BOX, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+};
+
+IntrinsicCheckResult
+IntrinsicChecker::check (const TyTy::FnType *fntype)
+{
+  auto it = intrinsic_rules.find (fntype->get_identifier ());
+  if (it == intrinsic_rules.end ())
+    {
+      rust_error_at (fntype->get_locus (), ErrorCode::E0093,
+                    "unrecognized intrinsic function: %qs",
+                    fntype->get_identifier ().c_str ());
+      return IntrinsicCheckResult::Invalid;
+    }
+  auto rule = &it->second;
+
+  if (fntype->get_substs ().size () != rule->generic_count)
+    {
+      rust_error_at (fntype->get_locus (), ErrorCode::E0094,
+                    "intrinsic has wrong number of type parameters: found "
+                    "%lu, expected %lu",
+                    (unsigned long) fntype->get_substs ().size (),
+                    (unsigned long) rule->generic_count);
+      return IntrinsicCheckResult::Invalid;
+    }
+
+  IntrinsicCheckResult result = IntrinsicCheckResult::Valid;
+
+  if (fntype->get_num_params () != rule->param_types.size ())
+    {
+      rust_error_at (fntype->get_locus (), ErrorCode::E0308,
+                    "intrinsic has wrong number of function parameters: found "
+                    "%lu, expected %lu",
+                    (unsigned long) fntype->get_params ().size (),
+                    (unsigned long) rule->param_types.size ());
+      result = IntrinsicCheckResult::Invalid;
+    }
+  else
+    {
+      for (size_t i = 0; i < rule->param_types.size (); i++)
+       {
+         const TyTy::BaseType *actual_param
+           = fntype->get_params ().at (i).get_type ();
+         IntrinsicRuleType expected_type = rule->param_types.at (i);
+
+         if (!check_type (actual_param, expected_type, fntype))
+           {
+             rust_error_at (fntype->get_locus (), ErrorCode::E0308,
+                            "intrinsic has wrong type");
+             result = IntrinsicCheckResult::Invalid;
+           }
+       }
+    }
+
+  if (!check_type (fntype->get_return_type (), rule->return_type, fntype))
+    {
+      rust_error_at (fntype->get_locus (), ErrorCode::E0308,
+                    "intrinsic has wrong type");
+      result = IntrinsicCheckResult::Invalid;
+    }
+
+  if (result == IntrinsicCheckResult::Invalid)
+    {
+      rust_inform (fntype->get_locus (), "expected fn pointer %qs",
+                  expected_intrinsic_as_string (fntype).c_str ());
+      rust_inform (fntype->get_locus (), "   found fn pointer %qs",
+                  found_intrinsic_as_string (fntype).c_str ());
+    }
+  return result;
+}
+
+bool
+IntrinsicChecker::check_type (const TyTy::BaseType *actual,
+                             IntrinsicRuleType expected,
+                             const TyTy::FnType *fntype)
+{
+  switch (expected)
+    {
+    case IRT::Bool:
+      return actual->get_kind () == TyTy::TypeKind::BOOL;
+    case IRT::F32:
+      return actual->get_kind () == TyTy::TypeKind::FLOAT
+            && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
+                 == TyTy::FloatType::FloatKind::F32;
+    case IRT::F64:
+      return actual->get_kind () == TyTy::TypeKind::FLOAT
+            && static_cast<const TyTy::FloatType *> (actual)->get_float_kind ()
+                 == TyTy::FloatType::FloatKind::F64;
+    case IRT::I32:
+      return actual->get_kind () == TyTy::TypeKind::INT
+            && static_cast<const TyTy::IntType *> (actual)->get_int_kind ()
+                 == TyTy::IntType::IntKind::I32;
+    case IRT::Isize:
+      return actual->get_kind () == TyTy::TypeKind::ISIZE;
+    case IRT::U8:
+      return actual->get_kind () == TyTy::TypeKind::UINT
+            && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
+                 == TyTy::UintType::UintKind::U8;
+    case IRT::U64:
+      return actual->get_kind () == TyTy::TypeKind::UINT
+            && static_cast<const TyTy::UintType *> (actual)->get_uint_kind ()
+                 == TyTy::UintType::UintKind::U64;
+    case IRT::Usize:
+      return actual->get_kind () == TyTy::TypeKind::USIZE;
+    case IRT::Unit:
+      return actual->is_unit ();
+    case IRT::Never:
+      return actual->get_kind () == TyTy::TypeKind::NEVER;
+
+    case IRT::FirstGeneric:
+    case IRT::SecondGeneric:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::PARAM)
+         return false;
+
+       auto param = static_cast<const TyTy::ParamType *> (actual);
+       size_t expected_index = (expected == IRT::FirstGeneric) ? 0 : 1;
+       if (fntype->get_substs ().size () <= expected_index)
+         return false;
+       auto expected_param
+         = fntype->get_substs ().at (expected_index).get_param_ty ();
+       return param->get_ty_ref () == expected_param->get_ty_ref ();
+      }
+    case IRT::ConstPtrFirstGeneric:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::POINTER)
+         return false;
+       auto ptr = static_cast<const TyTy::PointerType *> (actual);
+       if (!ptr->is_const ())
+         return false;
+       return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
+                          fntype);
+      }
+    case IRT::MutPtrFirstGeneric:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::POINTER)
+         return false;
+       auto ptr = static_cast<const TyTy::PointerType *> (actual);
+       if (!ptr->is_mutable ())
+         return false;
+       return check_type (ptr->get_base (), IntrinsicRuleType::FirstGeneric,
+                          fntype);
+      }
+    case IRT::RefFirstGeneric:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::REF)
+         return false;
+       auto ref = static_cast<const TyTy::ReferenceType *> (actual);
+       if (ref->is_mutable ())
+         return false;
+       return check_type (ref->get_base (), IntrinsicRuleType::FirstGeneric,
+                          fntype);
+      }
+    case IRT::RefAdt:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::REF)
+         return false;
+       auto ref = static_cast<const TyTy::ReferenceType *> (actual);
+       if (ref->is_mutable ())
+         return false;
+       return ref->get_base ()->get_kind () == TyTy::TypeKind::ADT;
+      }
+    case IRT::MutPtrU8:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::POINTER)
+         return false;
+       auto ptr = static_cast<const TyTy::PointerType *> (actual);
+       if (!ptr->is_mutable ())
+         return false;
+       return check_type (ptr->get_base (), IRT::U8, fntype);
+      }
+    case IRT::RefStaticStr:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::REF)
+         return false;
+       auto ref = static_cast<const TyTy::ReferenceType *> (actual);
+       if (ref->is_mutable ())
+         return false;
+       return ref->get_base ()->get_kind () == TyTy::TypeKind::STR;
+      }
+    case IRT::AssocTypePlaceholder:
+      return actual->get_kind () == TyTy::TypeKind::PLACEHOLDER;
+
+    case IRT::TupleFirstGenericAndBool:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::TUPLE)
+         return false;
+       auto tuple = static_cast<const TyTy::TupleType *> (actual);
+       if (tuple->num_fields () != 2)
+         return false;
+       return tuple->get_field (1)->get_kind () == TyTy::TypeKind::BOOL
+              && check_type (tuple->get_field (0),
+                             IntrinsicRuleType::FirstGeneric, fntype);
+      }
+
+    case IRT::Fn_MutPtrU8:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::FNPTR)
+         return false;
+       auto fn = static_cast<const TyTy::FnPtr *> (actual);
+       if (!fn->get_return_type ()->is_unit ())
+         return false;
+       if (fn->get_num_params () != 1)
+         return false;
+       return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype);
+      }
+    case IRT::Fn_MutPtrU8MutPtrU8:
+      {
+       if (actual->get_kind () != TyTy::TypeKind::FNPTR)
+         return false;
+       auto fn = static_cast<const TyTy::FnPtr *> (actual);
+       if (!fn->get_return_type ()->is_unit ())
+         return false;
+       if (fn->get_num_params () != 2)
+         return false;
+       return check_type (fn->get_param_type_at (0), IRT::MutPtrU8, fntype)
+              && check_type (fn->get_param_type_at (1), IRT::MutPtrU8, fntype);
+      }
+
+    default:
+      rust_unreachable ();
+    };
+  return true;
+}
+
+static std::string
+to_string (const TyTy::BaseType *type, const TyTy::FnType *fntype)
+{
+  switch (type->get_kind ())
+    {
+    case TyTy::TypeKind::BOOL:
+      return "bool";
+    case TyTy::TypeKind::USIZE:
+      return "usize";
+    case TyTy::TypeKind::ISIZE:
+      return "isize";
+    case TyTy::TypeKind::NEVER:
+      return "!";
+    case TyTy::TypeKind::STR:
+      return "str";
+
+    case TyTy::TypeKind::INT:
+      {
+       auto int_ty = static_cast<const TyTy::IntType *> (type);
+       switch (int_ty->get_int_kind ())
+         {
+         case TyTy::IntType::IntKind::I8:
+           return "i8";
+         case TyTy::IntType::IntKind::I16:
+           return "i16";
+         case TyTy::IntType::IntKind::I32:
+           return "i32";
+         case TyTy::IntType::IntKind::I64:
+           return "i64";
+         case TyTy::IntType::IntKind::I128:
+           return "i128";
+         }
+       rust_unreachable ();
+      }
+
+    case TyTy::TypeKind::UINT:
+      {
+       auto uint_ty = static_cast<const TyTy::UintType *> (type);
+       switch (uint_ty->get_uint_kind ())
+         {
+         case TyTy::UintType::UintKind::U8:
+           return "u8";
+         case TyTy::UintType::UintKind::U16:
+           return "u16";
+         case TyTy::UintType::UintKind::U32:
+           return "u32";
+         case TyTy::UintType::UintKind::U64:
+           return "u64";
+         case TyTy::UintType::UintKind::U128:
+           return "u128";
+         }
+       rust_unreachable ();
+      }
+
+    case TyTy::TypeKind::FLOAT:
+      {
+       auto float_ty = static_cast<const TyTy::FloatType *> (type);
+       switch (float_ty->get_float_kind ())
+         {
+         case TyTy::FloatType::FloatKind::F32:
+           return "f32";
+         case TyTy::FloatType::FloatKind::F64:
+           return "f64";
+         }
+       rust_unreachable ();
+      }
+
+    case TyTy::TypeKind::PARAM:
+      {
+       auto param = static_cast<const TyTy::ParamType *> (type);
+       if (fntype != nullptr)
+         {
+           auto substs = fntype->get_substs ();
+           for (size_t i = 0; i < substs.size (); i++)
+             {
+               if (substs[i].get_param_ty ()->get_ty_ref ()
+                   == param->get_ty_ref ())
+                 return "P" + std::to_string (i);
+             }
+         }
+       return param->get_symbol ();
+      }
+
+    case TyTy::TypeKind::POINTER:
+      {
+       auto ptr = static_cast<const TyTy::PointerType *> (type);
+       std::string prefix = ptr->is_mutable () ? "*mut "
+                            : ptr->is_const () ? "*const "
+                                               : "*";
+       return prefix + to_string (ptr->get_base (), fntype);
+      }
+
+    case TyTy::TypeKind::REF:
+      {
+       auto ref = static_cast<const TyTy::ReferenceType *> (type);
+       std::string prefix = ref->is_mutable () ? "&mut " : "&";
+       return prefix + to_string (ref->get_base (), fntype);
+      }
+
+    case TyTy::TypeKind::TUPLE:
+      {
+       auto tuple = static_cast<const TyTy::TupleType *> (type);
+       if (tuple->num_fields () == 0)
+         return "()";
+
+       std::string res = "(";
+       for (size_t i = 0; i < tuple->num_fields (); i++)
+         {
+           if (i > 0)
+             res += ", ";
+           res += to_string (tuple->get_field (i), fntype);
+         }
+       res += ")";
+       return res;
+      }
+
+    case TyTy::TypeKind::FNPTR:
+      {
+       auto fnptr = static_cast<const TyTy::FnPtr *> (type);
+       std::string res = "fn(";
+       for (size_t i = 0; i < fnptr->get_num_params (); i++)
+         {
+           if (i > 0)
+             res += ", ";
+           res += to_string (fnptr->get_param_type_at (i), fntype);
+         }
+       res += ")";
+       if (!fnptr->get_return_type ()->is_unit ()
+           || fnptr->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
+         {
+           res += " -> ";
+           res += to_string (fnptr->get_return_type (), fntype);
+         }
+       return res;
+      }
+
+    case TyTy::TypeKind::ADT:
+      {
+       auto adt = static_cast<const TyTy::ADTType *> (type);
+       return adt->get_name ();
+      }
+
+    case TyTy::TypeKind::PLACEHOLDER:
+      {
+       auto ph = static_cast<const TyTy::PlaceholderType *> (type);
+       return "<" + ph->get_symbol () + ">";
+      }
+
+    default:
+      return type->as_string ();
+    }
+}
+
+static std::string
+to_string (IntrinsicRuleType ty)
+{
+  switch (ty)
+    {
+    case IRT::Bool:
+      return "bool";
+    case IRT::F32:
+      return "f32";
+    case IRT::F64:
+      return "f64";
+    case IRT::I32:
+      return "i32";
+    case IRT::Isize:
+      return "isize";
+    case IRT::U8:
+      return "u8";
+    case IRT::U64:
+      return "u64";
+    case IRT::Usize:
+      return "usize";
+    case IRT::Unit:
+      return "()";
+    case IRT::Never:
+      return "!";
+
+    case IRT::FirstGeneric:
+      return "P0";
+    case IRT::SecondGeneric:
+      return "P1";
+
+    case IRT::ConstPtrFirstGeneric:
+      return "*const P0";
+    case IRT::MutPtrFirstGeneric:
+      return "*mut P0";
+    case IRT::RefFirstGeneric:
+      return "&P0";
+
+    case IRT::RefAdt:
+      return "&<ADT>";
+    case IRT::MutPtrU8:
+      return "*mut u8";
+    case IRT::RefStaticStr:
+      return "&'static str";
+    case IRT::AssocTypePlaceholder:
+      return "<AssocType>";
+
+    case IRT::TupleFirstGenericAndBool:
+      return "(P0, bool)";
+
+    case IRT::Fn_MutPtrU8:
+      return "fn(*mut u8)";
+    case IRT::Fn_MutPtrU8MutPtrU8:
+      return "fn(*mut u8, *mut u8)";
+    };
+  rust_unreachable ();
+}
+
+std::string
+IntrinsicChecker::expected_intrinsic_as_string (const TyTy::FnType *fntype)
+{
+  auto it = intrinsic_rules.find (fntype->get_identifier ());
+  rust_assert (it != intrinsic_rules.end ());
+  auto rule = &it->second;
+  std::stringstream result;
+  result << "extern \"rust-intrinsic\" fn(";
+  if (rule->param_types.size () > 0)
+    {
+      for (size_t i = 0; i < rule->param_types.size (); i++)
+       {
+         if (i != 0)
+           result << ", ";
+         result << to_string (rule->param_types.at (i));
+       }
+    }
+  result << ")";
+  if (rule->return_type != IntrinsicRuleType::Unit)
+    {
+      result << " -> " << to_string (rule->return_type);
+    }
+  return result.str ();
+}
+
+std::string
+IntrinsicChecker::found_intrinsic_as_string (const TyTy::FnType *fntype)
+{
+  std::stringstream result;
+  result << "extern \"rust-intrinsic\" fn(";
+  if (fntype->get_num_params () > 0)
+    {
+      const auto &params = fntype->get_params ();
+      for (size_t i = 0; i < params.size (); i++)
+       {
+         if (i != 0)
+           result << ", ";
+         result << to_string (params.at (i).get_type (), fntype);
+       }
+    }
+  result << ")";
+  if (!fntype->get_return_type ()->is_unit ()
+      || fntype->get_return_type ()->get_kind () == TyTy::TypeKind::NEVER)
+    {
+      result << " -> " << to_string (fntype->get_return_type (), fntype);
+    }
+  return result.str ();
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.h 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.h
new file mode 100644
index 000000000..8539982b9
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_TYPE_CHECK_INTRINSIC_H
+#define RUST_HIR_TYPE_CHECK_INTRINSIC_H
+
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+enum class IntrinsicRuleType
+{
+  Bool,
+  F32,
+  F64,
+  I32,
+  Isize,
+  U8,
+  U64,
+  Usize,
+  Unit,
+  Never,
+
+  FirstGeneric,         // <T>
+  SecondGeneric, // <U>
+
+  ConstPtrFirstGeneric, // *const T
+  MutPtrFirstGeneric,  // *mut T
+  RefFirstGeneric,     // &T
+
+  RefAdt,   // for caller_location() -> &'static 
crate::panic::Location<'static>
+  MutPtrU8, // *mut u8
+  RefStaticStr, // &'static str
+  AssocTypePlaceholder,
+  // for discriminant_value<T>(v: &T) -> <T as DiscriminantKind>::Discriminant
+
+  TupleFirstGenericAndBool, // (T, bool)
+
+  Fn_MutPtrU8,        // fn(*mut u8)
+  Fn_MutPtrU8MutPtrU8, // fn(*mut u8, *mut u8)
+};
+
+struct IntrinsicRules
+{
+  size_t generic_count;
+  std::vector<IntrinsicRuleType> param_types;
+  IntrinsicRuleType return_type;
+};
+
+enum class IntrinsicCheckResult
+{
+  Valid,
+  Invalid,
+};
+
+class IntrinsicChecker
+{
+public:
+  static IntrinsicCheckResult check (const TyTy::FnType *fntype);
+
+private:
+  static const std::unordered_map<std::string, IntrinsicRules> intrinsic_rules;
+  static bool check_type (const TyTy::BaseType *actual,
+                         IntrinsicRuleType expected,
+                         const TyTy::FnType *fntype);
+  static std::string expected_intrinsic_as_string (const TyTy::FnType *fntype);
+  static std::string found_intrinsic_as_string (const TyTy::FnType *fntype);
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif
diff --git a/gcc/testsuite/rust/compile/ctlz.rs 
b/gcc/testsuite/rust/compile/ctlz.rs
index 625b8847b..7a4a40b63 100644
--- a/gcc/testsuite/rust/compile/ctlz.rs
+++ b/gcc/testsuite/rust/compile/ctlz.rs
@@ -9,7 +9,7 @@ pub trait Sized {}
 pub trait Copy {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
 }
 
 fn main() {
diff --git a/gcc/testsuite/rust/compile/ctlz_nonzero.rs 
b/gcc/testsuite/rust/compile/ctlz_nonzero.rs
index 74c3fb96a..7fea4a4ee 100644
--- a/gcc/testsuite/rust/compile/ctlz_nonzero.rs
+++ b/gcc/testsuite/rust/compile/ctlz_nonzero.rs
@@ -9,7 +9,7 @@ pub trait Sized {}
 pub trait Copy {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
 }
 
 fn main() {
diff --git a/gcc/testsuite/rust/compile/cttz.rs 
b/gcc/testsuite/rust/compile/cttz.rs
index 2267bdeff..e8ef73ee9 100644
--- a/gcc/testsuite/rust/compile/cttz.rs
+++ b/gcc/testsuite/rust/compile/cttz.rs
@@ -9,7 +9,7 @@ pub trait Sized {}
 pub trait Copy {}
 
 extern "rust-intrinsic" {
-    pub fn cttz<T>(x: T) -> u32;
+    pub fn cttz<T>(x: T) -> T;
 }
 
 fn main() {
diff --git a/gcc/testsuite/rust/compile/cttz_nonzero.rs 
b/gcc/testsuite/rust/compile/cttz_nonzero.rs
index e8e49dbce..c02e506d5 100644
--- a/gcc/testsuite/rust/compile/cttz_nonzero.rs
+++ b/gcc/testsuite/rust/compile/cttz_nonzero.rs
@@ -9,7 +9,7 @@ pub trait Sized {}
 pub trait Copy {}
 
 extern "rust-intrinsic" {
-    pub fn cttz_nonzero<T>(x: T) -> u32;
+    pub fn cttz_nonzero<T>(x: T) -> T;
 }
 
 fn main() {
diff --git a/gcc/testsuite/rust/compile/intrinsic-checker.rs 
b/gcc/testsuite/rust/compile/intrinsic-checker.rs
new file mode 100644
index 000000000..e629729d7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/intrinsic-checker.rs
@@ -0,0 +1,27 @@
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+    fn foo(); // { dg-error "unrecognized intrinsic function: .foo." }
+
+    fn size_of<T, U>() -> usize; // { dg-error "intrinsic has wrong number of 
type parameters: found 2, expected 1" }
+
+    fn abort(x: i32) -> !; // { dg-error "intrinsic has wrong number of 
function parameters: found 1, expected 0" }
+
+    fn offset<T>(dst: usize, offset: isize) -> *const T;
+    // { dg-error "intrinsic has wrong type" "" { target *-*-* } .-1 }
+    // { dg-message "expected fn pointer .extern \"rust-intrinsic\" 
fn\\(\\*const P0, isize\\) -> \\*const P0." "" { target *-*-* } .-2 }
+    // { dg-message "found fn pointer .extern \"rust-intrinsic\" fn\\(usize, 
isize\\) -> \\*const P0." "" { target *-*-* } .-3 }
+
+    fn add_with_overflow<T>(x: T, y: i32) -> (T, bool);
+    // { dg-error "intrinsic has wrong type" "" { target *-*-* } .-1 }
+
+    fn catch_unwind(try_fn: usize, data: *mut u8, catch_fn: fn(*mut u8, *mut 
u8)) -> i32;
+    // { dg-error "intrinsic has wrong type" "" { target *-*-* } .-1 }
+
+    fn transmute<T, U>(e: T) -> usize;
+    // { dg-error "intrinsic has wrong type" "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-4245.rs 
b/gcc/testsuite/rust/compile/issue-4245.rs
index 65942a5d9..9b5577de3 100644
--- a/gcc/testsuite/rust/compile/issue-4245.rs
+++ b/gcc/testsuite/rust/compile/issue-4245.rs
@@ -9,5 +9,5 @@ pub trait Sized {}
 
 #[cfg(not(cg_gcc))]
 extern "rust-intrinsic" {
-    fn copy_nonoverlapping<T>(src: &T, dst: &mut T, count: usize);
+    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
 }
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-3.rs 
b/gcc/testsuite/rust/compile/torture/intrinsics-3.rs
index 66ef330ff..c34d7441d 100644
--- a/gcc/testsuite/rust/compile/torture/intrinsics-3.rs
+++ b/gcc/testsuite/rust/compile/torture/intrinsics-3.rs
@@ -4,9 +4,9 @@
 #![feature(intrinsics)]
 
 extern "rust-intrinsic" {
-    fn not_an_intrinsic();
+    fn not_an_intrinsic(); // { dg-error "unrecognized intrinsic function: 
.not_an_intrinsic." }
 }
 
 fn main() {
-    unsafe { not_an_intrinsic() }; // { dg-error "unrecognized intrinsic 
function: .not_an_intrinsic." }
+    unsafe { not_an_intrinsic() };
 }
diff --git a/gcc/testsuite/rust/execute/torture/ctlz.rs 
b/gcc/testsuite/rust/execute/torture/ctlz.rs
index bd8afba22..089c8250b 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_i16.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_i16.rs
index 90db2e531..03e6a3976 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_i16.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_i16.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_i32.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_i32.rs
index d49668751..cb7a52c44 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_i32.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_i32.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_i64.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_i64.rs
index feb4694d0..5e1f677ed 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_i64.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_i64.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_i8.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_i8.rs
index 204999f60..8e3c697eb 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_i8.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_i8.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero.rs
index 3476ab2b9..b380054e4 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i16.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i16.rs
index e8593ab22..98bb838bb 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i16.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i16.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i32.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i32.rs
index 2c5afd3c1..1b81d73b8 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i32.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i32.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i64.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i64.rs
index b34f4ca16..7f404abbb 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i64.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i64.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i8.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i8.rs
index 0f6c7f0c9..3c10a83de 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i8.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_i8.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u16.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u16.rs
index da0521c1c..186c23c33 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u16.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u16.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u32.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u32.rs
index b1224067b..75496aa8d 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u32.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u32.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u64.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u64.rs
index 9297c9d50..c972056cd 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u64.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u64.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u8.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u8.rs
index d7baa555a..6d8813428 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u8.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_nonzero_u8.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz_nonzero<T>(x: T) -> u32;
+    pub fn ctlz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_u16.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_u16.rs
index ded1b7458..5b052b298 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_u16.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_u16.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_u32.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_u32.rs
index cb0b20cb3..2f77e8a06 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_u32.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_u32.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_u64.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_u64.rs
index bcf478e73..cac311d5b 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_u64.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_u64.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/ctlz_u8.rs 
b/gcc/testsuite/rust/execute/torture/ctlz_u8.rs
index 8907a86cb..4eef234a0 100644
--- a/gcc/testsuite/rust/execute/torture/ctlz_u8.rs
+++ b/gcc/testsuite/rust/execute/torture/ctlz_u8.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn ctlz<T>(x: T) -> u32;
+    pub fn ctlz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/cttz.rs 
b/gcc/testsuite/rust/execute/torture/cttz.rs
index d9f4656de..6ddf970ab 100644
--- a/gcc/testsuite/rust/execute/torture/cttz.rs
+++ b/gcc/testsuite/rust/execute/torture/cttz.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn cttz<T>(x: T) -> u32;
+    pub fn cttz<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
diff --git a/gcc/testsuite/rust/execute/torture/cttz_nonzero.rs 
b/gcc/testsuite/rust/execute/torture/cttz_nonzero.rs
index 749dffaf6..6b23d66d5 100644
--- a/gcc/testsuite/rust/execute/torture/cttz_nonzero.rs
+++ b/gcc/testsuite/rust/execute/torture/cttz_nonzero.rs
@@ -7,7 +7,7 @@
 pub trait Sized {}
 
 extern "rust-intrinsic" {
-    pub fn cttz_nonzero<T>(x: T) -> u32;
+    pub fn cttz_nonzero<T>(x: T) -> T;
     pub fn abort() -> !;
 }
 
-- 
2.54.0

Reply via email to