about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/rustdoc-js-std/parser-errors.js19
-rw-r--r--tests/rustdoc-js-std/parser-hof.js712
-rw-r--r--tests/rustdoc-js-std/parser-weird-queries.js9
-rw-r--r--tests/rustdoc-js/hof.js176
-rw-r--r--tests/rustdoc-js/hof.rs12
-rw-r--r--tests/ui-fulldeps/stable-mir/check_transform.rs147
-rw-r--r--tests/ui/consts/const-eval/erroneous-const.stderr15
-rw-r--r--tests/ui/consts/const-eval/erroneous-const2.rs19
-rw-r--r--tests/ui/consts/const-eval/erroneous-const2.stderr15
-rw-r--r--tests/ui/consts/const-eval/unused-broken-const-late.stderr11
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr17
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr17
-rw-r--r--tests/ui/consts/required-consts/collect-in-called-fn.rs (renamed from tests/ui/consts/const-eval/unused-broken-const-late.rs)18
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr14
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-drop.rs33
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr17
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-fn.rs35
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-forget.rs32
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr14
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-move.rs33
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr17
-rw-r--r--tests/ui/consts/required-consts/collect-in-dead-vtable.rs41
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr17
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr17
-rw-r--r--tests/ui/consts/required-consts/interpret-in-const-called-fn.rs (renamed from tests/ui/consts/const-eval/erroneous-const.rs)13
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr27
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr27
-rw-r--r--tests/ui/consts/required-consts/interpret-in-promoted.rs15
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.noopt.stderr17
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.opt.stderr17
-rw-r--r--tests/ui/consts/required-consts/interpret-in-static.rs21
31 files changed, 1508 insertions, 86 deletions
diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js
index 16d171260da..ffd169812b6 100644
--- a/tests/rustdoc-js-std/parser-errors.js
+++ b/tests/rustdoc-js-std/parser-errors.js
@@ -114,7 +114,7 @@ const PARSED = [
         original: "(p -> p",
         returned: [],
         userQuery: "(p -> p",
-        error: "Unexpected `-` after `(`",
+        error: "Unclosed `(`",
     },
     {
         query: "::a::b",
@@ -195,7 +195,7 @@ const PARSED = [
         original: "a (b:",
         returned: [],
         userQuery: "a (b:",
-        error: "Expected `,`, `:` or `->`, found `(`",
+        error: "Unclosed `(`",
     },
     {
         query: "_:",
@@ -330,7 +330,7 @@ const PARSED = [
         original: 'a<->',
         returned: [],
         userQuery: 'a<->',
-        error: 'Unexpected `-` after `<`',
+        error: 'Unclosed `<`',
     },
     {
         query: "a<a>:",
@@ -357,7 +357,16 @@ const PARSED = [
         original: "a,:",
         returned: [],
         userQuery: "a,:",
-        error: 'Unexpected `,` in type filter (before `:`)',
+        error: 'Expected type filter before `:`',
+    },
+    {
+        query: "a!:",
+        elems: [],
+        foundElems: 0,
+        original: "a!:",
+        returned: [],
+        userQuery: "a!:",
+        error: 'Unexpected `!` in type filter (before `:`)',
     },
     {
         query: "  a<>  :",
@@ -366,7 +375,7 @@ const PARSED = [
         original: "a<>  :",
         returned: [],
         userQuery: "a<>  :",
-        error: 'Unexpected `<` in type filter (before `:`)',
+        error: 'Expected `,`, `:` or `->` after `>`, found `:`',
     },
     {
         query: "mod : :",
diff --git a/tests/rustdoc-js-std/parser-hof.js b/tests/rustdoc-js-std/parser-hof.js
new file mode 100644
index 00000000000..0b99c45b7a9
--- /dev/null
+++ b/tests/rustdoc-js-std/parser-hof.js
@@ -0,0 +1,712 @@
+const PARSED = [
+    // ML-style HOF
+    {
+        query: "(-> F<P>)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [
+                            {
+                                name: "p",
+                                fullPath: ["p"],
+                                pathWithoutLast: [],
+                                pathLast: "p",
+                                generics: [],
+                            },
+                        ],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(-> F<P>)",
+        returned: [],
+        userQuery: "(-> f<p>)",
+        error: null,
+    },
+    {
+        query: "(-> P)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(-> P)",
+        returned: [],
+        userQuery: "(-> p)",
+        error: null,
+    },
+    {
+        query: "(->,a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(->,a)",
+        returned: [],
+        userQuery: "(->,a)",
+        error: null,
+    },
+    {
+        query: "(F<P> ->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "f",
+                fullPath: ["f"],
+                pathWithoutLast: [],
+                pathLast: "f",
+                generics: [
+                    {
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                    },
+                ],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(F<P> ->)",
+        returned: [],
+        userQuery: "(f<p> ->)",
+        error: null,
+    },
+    {
+        query: "(P ->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "p",
+                fullPath: ["p"],
+                pathWithoutLast: [],
+                pathLast: "p",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(P ->)",
+        returned: [],
+        userQuery: "(p ->)",
+        error: null,
+    },
+    {
+        query: "(,a->)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(,a->)",
+        returned: [],
+        userQuery: "(,a->)",
+        error: null,
+    },
+    {
+        query: "(aaaaa->a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [{
+                name: "aaaaa",
+                fullPath: ["aaaaa"],
+                pathWithoutLast: [],
+                pathLast: "aaaaa",
+                generics: [],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(aaaaa->a)",
+        returned: [],
+        userQuery: "(aaaaa->a)",
+        error: null,
+    },
+    {
+        query: "(aaaaa, b -> a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: "primitive:(aaaaa, b -> a)",
+        elems: [{
+            name: "->",
+            fullPath: ["->"],
+            pathWithoutLast: [],
+            pathLast: "->",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "primitive:(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: "x, trait:(aaaaa, b -> a)",
+        elems: [
+            {
+                name: "x",
+                fullPath: ["x"],
+                pathWithoutLast: [],
+                pathLast: "x",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "->",
+                fullPath: ["->"],
+                pathWithoutLast: [],
+                pathLast: "->",
+                generics: [
+                    {
+                        name: "aaaaa",
+                        fullPath: ["aaaaa"],
+                        pathWithoutLast: [],
+                        pathLast: "aaaaa",
+                        generics: [],
+                        typeFilter: -1,
+                    },
+                    {
+                        name: "b",
+                        fullPath: ["b"],
+                        pathWithoutLast: [],
+                        pathLast: "b",
+                        generics: [],
+                        typeFilter: -1,
+                    },
+                ],
+                bindings: [
+                    [
+                        "output",
+                        [{
+                            name: "a",
+                            fullPath: ["a"],
+                            pathWithoutLast: [],
+                            pathLast: "a",
+                            generics: [],
+                            typeFilter: -1,
+                        }],
+                    ],
+                ],
+                typeFilter: 10,
+            }
+        ],
+        foundElems: 2,
+        original: "x, trait:(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "x, trait:(aaaaa, b -> a)",
+        error: null,
+    },
+    // Rust-style HOF
+    {
+        query: "Fn () -> F<P>",
+        elems: [{
+            name: "fn",
+            fullPath: ["fn"],
+            pathWithoutLast: [],
+            pathLast: "fn",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "f",
+                        fullPath: ["f"],
+                        pathWithoutLast: [],
+                        pathLast: "f",
+                        generics: [
+                            {
+                                name: "p",
+                                fullPath: ["p"],
+                                pathWithoutLast: [],
+                                pathLast: "p",
+                                generics: [],
+                            },
+                        ],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "Fn () -> F<P>",
+        returned: [],
+        userQuery: "fn () -> f<p>",
+        error: null,
+    },
+    {
+        query: "FnMut() -> P",
+        elems: [{
+            name: "fnmut",
+            fullPath: ["fnmut"],
+            pathWithoutLast: [],
+            pathLast: "fnmut",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "FnMut() -> P",
+        returned: [],
+        userQuery: "fnmut() -> p",
+        error: null,
+    },
+    {
+        query: "(FnMut() -> P)",
+        elems: [{
+            name: "fnmut",
+            fullPath: ["fnmut"],
+            pathWithoutLast: [],
+            pathLast: "fnmut",
+            generics: [],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "(FnMut() -> P)",
+        returned: [],
+        userQuery: "(fnmut() -> p)",
+        error: null,
+    },
+    {
+        query: "Fn(F<P>)",
+        elems: [{
+            name: "fn",
+            fullPath: ["fn"],
+            pathWithoutLast: [],
+            pathLast: "fn",
+            generics: [{
+                name: "f",
+                fullPath: ["f"],
+                pathWithoutLast: [],
+                pathLast: "f",
+                generics: [
+                    {
+                        name: "p",
+                        fullPath: ["p"],
+                        pathWithoutLast: [],
+                        pathLast: "p",
+                        generics: [],
+                    },
+                ],
+                typeFilter: -1,
+            }],
+            bindings: [
+                [
+                    "output",
+                    [],
+                ],
+            ],
+            typeFilter: -1,
+        }],
+        foundElems: 1,
+        original: "Fn(F<P>)",
+        returned: [],
+        userQuery: "fn(f<p>)",
+        error: null,
+    },
+    {
+        query: "primitive:fnonce(aaaaa, b) -> a",
+        elems: [{
+            name: "fnonce",
+            fullPath: ["fnonce"],
+            pathWithoutLast: [],
+            pathLast: "fnonce",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: -1,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: -1,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:fnonce(aaaaa, b) -> a",
+        returned: [],
+        userQuery: "primitive:fnonce(aaaaa, b) -> a",
+        error: null,
+    },
+    {
+        query: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        elems: [{
+            name: "fnonce",
+            fullPath: ["fnonce"],
+            pathWithoutLast: [],
+            pathLast: "fnonce",
+            generics: [
+                {
+                    name: "aaaaa",
+                    fullPath: ["aaaaa"],
+                    pathWithoutLast: [],
+                    pathLast: "aaaaa",
+                    generics: [],
+                    typeFilter: -1,
+                },
+                {
+                    name: "b",
+                    fullPath: ["b"],
+                    pathWithoutLast: [],
+                    pathLast: "b",
+                    generics: [],
+                    typeFilter: 0,
+                },
+            ],
+            bindings: [
+                [
+                    "output",
+                    [{
+                        name: "a",
+                        fullPath: ["a"],
+                        pathWithoutLast: [],
+                        pathLast: "a",
+                        generics: [],
+                        typeFilter: 10,
+                    }],
+                ],
+            ],
+            typeFilter: 1,
+        }],
+        foundElems: 1,
+        original: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        returned: [],
+        userQuery: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
+        error: null,
+    },
+    {
+        query: "x, trait:fn(aaaaa, b -> a)",
+        elems: [
+            {
+                name: "x",
+                fullPath: ["x"],
+                pathWithoutLast: [],
+                pathLast: "x",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "fn",
+                fullPath: ["fn"],
+                pathWithoutLast: [],
+                pathLast: "fn",
+                generics: [
+                    {
+                        name: "->",
+                        fullPath: ["->"],
+                        pathWithoutLast: [],
+                        pathLast: "->",
+                        generics: [
+                            {
+                                name: "aaaaa",
+                                fullPath: ["aaaaa"],
+                                pathWithoutLast: [],
+                                pathLast: "aaaaa",
+                                generics: [],
+                                typeFilter: -1,
+                            },
+                            {
+                                name: "b",
+                                fullPath: ["b"],
+                                pathWithoutLast: [],
+                                pathLast: "b",
+                                generics: [],
+                                typeFilter: -1,
+                            },
+                        ],
+                        bindings: [
+                            [
+                                "output",
+                                [{
+                                    name: "a",
+                                    fullPath: ["a"],
+                                    pathWithoutLast: [],
+                                    pathLast: "a",
+                                    generics: [],
+                                    typeFilter: -1,
+                                }],
+                            ],
+                        ],
+                        typeFilter: -1,
+                    },
+                ],
+                bindings: [
+                    [
+                        "output",
+                        [],
+                    ]
+                ],
+                typeFilter: 10,
+            }
+        ],
+        foundElems: 2,
+        original: "x, trait:fn(aaaaa, b -> a)",
+        returned: [],
+        userQuery: "x, trait:fn(aaaaa, b -> a)",
+        error: null,
+    },
+    {
+        query: 'a,b(c)',
+        elems: [
+            {
+                name: "a",
+                fullPath: ["a"],
+                pathWithoutLast: [],
+                pathLast: "a",
+                generics: [],
+                typeFilter: -1,
+            },
+            {
+                name: "b",
+                fullPath: ["b"],
+                pathWithoutLast: [],
+                pathLast: "b",
+                generics: [{
+                    name: "c",
+                    fullPath: ["c"],
+                    pathWithoutLast: [],
+                    pathLast: "c",
+                    generics: [],
+                    typeFilter: -1,
+                }],
+                bindings: [
+                    [
+                        "output",
+                        [],
+                    ]
+                ],
+                typeFilter: -1,
+            }
+        ],
+        foundElems: 2,
+        original: "a,b(c)",
+        returned: [],
+        userQuery: "a,b(c)",
+        error: null,
+    },
+];
diff --git a/tests/rustdoc-js-std/parser-weird-queries.js b/tests/rustdoc-js-std/parser-weird-queries.js
index 26b8c32d680..499b82a3469 100644
--- a/tests/rustdoc-js-std/parser-weird-queries.js
+++ b/tests/rustdoc-js-std/parser-weird-queries.js
@@ -38,15 +38,6 @@ const PARSED = [
         error: null,
     },
     {
-        query: 'a,b(c)',
-        elems: [],
-        foundElems: 0,
-        original: "a,b(c)",
-        returned: [],
-        userQuery: "a,b(c)",
-        error: "Expected `,`, `:` or `->`, found `(`",
-    },
-    {
         query: 'aaa,a',
         elems: [
             {
diff --git a/tests/rustdoc-js/hof.js b/tests/rustdoc-js/hof.js
new file mode 100644
index 00000000000..5e6c9d83c7c
--- /dev/null
+++ b/tests/rustdoc-js/hof.js
@@ -0,0 +1,176 @@
+// exact-check
+
+const EXPECTED = [
+    // not a HOF query
+    {
+        'query': 'u32 -> !',
+        'others': [],
+    },
+
+    // ML-style higher-order function notation
+    {
+        'query': 'bool, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'u8, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'i8, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'char, (u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': '(first<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': '(second<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': '(third<u32> -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': '(u32 -> !) -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+            {"path": "hof", "name": "fn_ptr"},
+            {"path": "hof", "name": "fn_mut"},
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': '(str, str -> i8) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(str ->) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(-> i8) -> ()',
+        'others': [
+            {"path": "hof", "name": "multiple"},
+        ],
+    },
+    {
+        'query': '(str -> str) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+    {
+        'query': '(i8 ->) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+    {
+        'query': '(-> str) -> ()',
+        // params and return are not the same
+        'others': [],
+    },
+
+    // Rust-style higher-order function notation
+    {
+        'query': 'bool, fn(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'u8, fnonce(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'u8, fn(u32) -> ! -> ()',
+        // fnonce != fn
+        'others': [],
+    },
+    {
+        'query': 'i8, fnmut(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'i8, fn(u32) -> ! -> ()',
+        // fnmut != fn
+        'others': [],
+    },
+    {
+        'query': 'char, fn(u32) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': 'char, fnmut(u32) -> ! -> ()',
+        // fn != fnmut
+        'others': [],
+    },
+    {
+        'query': 'fn(first<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'fnonce(second<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_once"},
+        ],
+    },
+    {
+        'query': 'fnmut(third<u32>) -> ! -> ()',
+        'others': [
+            {"path": "hof", "name": "fn_mut"},
+        ],
+    },
+    {
+        'query': 'fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_"},
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+    {
+        'query': 'trait:fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_"},
+        ],
+    },
+    {
+        'query': 'primitive:fn(u32) -> ! -> ()',
+        'others': [
+            // fn matches primitive:fn and trait:Fn
+            {"path": "hof", "name": "fn_ptr"},
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/hof.rs b/tests/rustdoc-js/hof.rs
new file mode 100644
index 00000000000..4d2c6e331ca
--- /dev/null
+++ b/tests/rustdoc-js/hof.rs
@@ -0,0 +1,12 @@
+#![feature(never_type)]
+
+pub struct First<T>(T);
+pub struct Second<T>(T);
+pub struct Third<T>(T);
+
+pub fn fn_ptr(_: fn (First<u32>) -> !, _: bool) {}
+pub fn fn_once(_: impl FnOnce (Second<u32>) -> !, _: u8) {}
+pub fn fn_mut(_: impl FnMut (Third<u32>) -> !, _: i8) {}
+pub fn fn_(_: impl Fn (u32) -> !, _: char) {}
+
+pub fn multiple(_: impl Fn(&'static str, &'static str) -> i8) {}
diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs
new file mode 100644
index 00000000000..e7d852a27df
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_transform.rs
@@ -0,0 +1,147 @@
+//@ run-pass
+//! Test a few methods to transform StableMIR.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+#![feature(ascii_char, ascii_char_variants)]
+
+extern crate rustc_hir;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_smir::rustc_internal;
+use stable_mir::mir::alloc::GlobalAlloc;
+use stable_mir::mir::mono::Instance;
+use stable_mir::mir::{Body, Constant, Operand, Rvalue, StatementKind, TerminatorKind};
+use stable_mir::ty::{Const, ConstantKind};
+use stable_mir::{CrateDef, CrateItems, ItemKind};
+use std::convert::TryFrom;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "input";
+
+/// This function uses the Stable MIR APIs to transform the MIR.
+fn test_transform() -> ControlFlow<()> {
+    // Find items in the local crate.
+    let items = stable_mir::all_local_items();
+
+    // Test fn_abi
+    let target_fn = *get_item(&items, (ItemKind::Fn, "dummy")).unwrap();
+    let instance = Instance::try_from(target_fn).unwrap();
+    let body = instance.body().unwrap();
+    check_msg(&body, "oops");
+
+    let new_msg = "new panic message";
+    let new_body = change_panic_msg(body, new_msg);
+    check_msg(&new_body, new_msg);
+
+    ControlFlow::Continue(())
+}
+
+/// Check that the body panic message matches the given message.
+fn check_msg(body: &Body, expected: &str) {
+    let msg = body
+        .blocks
+        .iter()
+        .find_map(|bb| match &bb.terminator.kind {
+            TerminatorKind::Call { args, .. } => {
+                assert_eq!(args.len(), 1, "Expected panic message, but found {args:?}");
+                let msg_const = match &args[0] {
+                    Operand::Constant(msg_const) => msg_const,
+                    Operand::Copy(place) | Operand::Move(place) => {
+                        assert!(place.projection.is_empty());
+                        bb.statements
+                            .iter()
+                            .find_map(|stmt| match &stmt.kind {
+                                StatementKind::Assign(
+                                    destination,
+                                    Rvalue::Use(Operand::Constant(msg_const)),
+                                ) if destination == place => Some(msg_const),
+                                _ => None,
+                            })
+                            .unwrap()
+                    }
+                };
+                let ConstantKind::Allocated(alloc) = msg_const.literal.kind() else {
+                    unreachable!()
+                };
+                assert_eq!(alloc.provenance.ptrs.len(), 1);
+
+                let alloc_prov_id = alloc.provenance.ptrs[0].1 .0;
+                let GlobalAlloc::Memory(val) = GlobalAlloc::from(alloc_prov_id) else {
+                    unreachable!()
+                };
+                let bytes = val.raw_bytes().unwrap();
+                Some(std::str::from_utf8(&bytes).unwrap().to_string())
+            }
+            _ => None,
+        })
+        .expect("Failed to find panic message");
+    assert_eq!(&msg, expected);
+}
+
+/// Modify body to use a different panic message.
+fn change_panic_msg(mut body: Body, new_msg: &str) -> Body {
+    for bb in &mut body.blocks {
+        match &mut bb.terminator.kind {
+            TerminatorKind::Call { args, .. } => {
+                let new_const = Const::from_str(new_msg);
+                args[0] = Operand::Constant(Constant {
+                    literal: new_const,
+                    span: bb.terminator.span,
+                    user_ty: None,
+                });
+            }
+            _ => {}
+        }
+    }
+    body
+}
+
+fn get_item<'a>(
+    items: &'a CrateItems,
+    item: (ItemKind, &str),
+) -> Option<&'a stable_mir::CrateItem> {
+    items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "transform_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_transform).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        #![feature(panic_internals)]
+        pub fn dummy() {{
+            core::panicking::panic_str("oops");
+        }}
+        "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/consts/const-eval/erroneous-const.stderr b/tests/ui/consts/const-eval/erroneous-const.stderr
deleted file mode 100644
index bd25e96c2cf..00000000000
--- a/tests/ui/consts/const-eval/erroneous-const.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/erroneous-const.rs:6:22
-   |
-LL |     const VOID: () = [()][2];
-   |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
-
-note: erroneous constant encountered
-  --> $DIR/erroneous-const.rs:13:13
-   |
-LL |             PrintName::<T>::VOID;
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/erroneous-const2.rs b/tests/ui/consts/const-eval/erroneous-const2.rs
deleted file mode 100644
index 61f2955f2d8..00000000000
--- a/tests/ui/consts/const-eval/erroneous-const2.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! Make sure we error on erroneous consts even if they are unused.
-#![allow(unconditional_panic)]
-
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed
-}
-
-pub static FOO: () = {
-    if false {
-        // This bad constant is only used in dead code in a static initializer... and yet we still
-        // must make sure that the build fails.
-        PrintName::<i32>::VOID; //~ constant
-    }
-};
-
-fn main() {
-    FOO
-}
diff --git a/tests/ui/consts/const-eval/erroneous-const2.stderr b/tests/ui/consts/const-eval/erroneous-const2.stderr
deleted file mode 100644
index 6a5839e3dfb..00000000000
--- a/tests/ui/consts/const-eval/erroneous-const2.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/erroneous-const2.rs:6:22
-   |
-LL |     const VOID: () = [()][2];
-   |                      ^^^^^^^ index out of bounds: the length is 1 but the index is 2
-
-note: erroneous constant encountered
-  --> $DIR/erroneous-const2.rs:13:9
-   |
-LL |         PrintName::<i32>::VOID;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.stderr b/tests/ui/consts/const-eval/unused-broken-const-late.stderr
deleted file mode 100644
index c2cf2f3813c..00000000000
--- a/tests/ui/consts/const-eval/unused-broken-const-late.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0080]: evaluation of `PrintName::<i32>::VOID` failed
-  --> $DIR/unused-broken-const-late.rs:8:22
-   |
-LL |     const VOID: () = panic!();
-   |                      ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unused-broken-const-late.rs:8:22
-   |
-   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
new file mode 100644
index 00000000000..c7ff1328917
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-called-fn.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn called::<i32>`
+  --> $DIR/collect-in-called-fn.rs:23:5
+   |
+LL |     called::<i32>();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
new file mode 100644
index 00000000000..c7ff1328917
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.opt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-called-fn.rs:9:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-called-fn.rs:9:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn called::<i32>`
+  --> $DIR/collect-in-called-fn.rs:23:5
+   |
+LL |     called::<i32>();
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.rs b/tests/ui/consts/required-consts/collect-in-called-fn.rs
index c4916061f9e..55133a10cd9 100644
--- a/tests/ui/consts/const-eval/unused-broken-const-late.rs
+++ b/tests/ui/consts/required-consts/collect-in-called-fn.rs
@@ -1,20 +1,24 @@
+//@revisions: noopt opt
 //@ build-fail
-//@ compile-flags: -O
+//@[opt] compile-flags: -O
 //! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
 //! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
 
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = panic!(); //~ERROR evaluation of `PrintName::<i32>::VOID` failed
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
-fn no_codegen<T>() {
+#[inline(never)]
+fn called<T>() {
     // Any function that is called is guaranteed to have all consts that syntactically
     // appear in its body evaluated, even if they only appear in dead code.
+    // This relies on mono-item collection checking `required_consts` in collected functions.
     if false {
-        let _ = PrintName::<T>::VOID;
+        let _ = Fail::<T>::C;
     }
 }
+
 pub fn main() {
-    no_codegen::<i32>();
+    called::<i32>();
 }
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
new file mode 100644
index 00000000000..b7010e78763
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.noopt.stderr
@@ -0,0 +1,14 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-drop.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-drop.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-drop.rs b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
new file mode 100644
index 00000000000..c9ffcec6903
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-drop.rs
@@ -0,0 +1,33 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        // Now it gest dropped implicitly, at the end of this scope.
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
new file mode 100644
index 00000000000..2162c35c837
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-fn.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-fn.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn not_called::<i32>`
+  --> $DIR/collect-in-dead-fn.rs:29:9
+   |
+LL |         not_called::<T>();
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-fn.rs b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
new file mode 100644
index 00000000000..9e6b1519153
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-fn.rs
@@ -0,0 +1,35 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but it is mentioned in dead code in a function that is
+// called. Make sure we still find this error.
+// This relies on mono-item collection checking `required_consts` in functions that syntactically
+// are called in collected functions (even inside dead code).
+#[inline(never)]
+fn not_called<T>() {
+    if false {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        not_called::<T>();
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-forget.rs b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
new file mode 100644
index 00000000000..720b7a499f7
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-forget.rs
@@ -0,0 +1,32 @@
+//@revisions: noopt opt
+//@build-pass
+//@[opt] compile-flags: -O
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!();
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        std::mem::forget(v);
+        // Now the destructor never gets "mentioned" so this build should *not* fail.
+        // IOW, this demonstrates that we are using a post-drop-elab notion of "mentioned".
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
new file mode 100644
index 00000000000..8c853127e04
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.noopt.stderr
@@ -0,0 +1,14 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-move.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-move.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn <Fail<i32> as std::ops::Drop>::drop`
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-move.rs b/tests/ui/consts/required-consts/collect-in-dead-move.rs
new file mode 100644
index 00000000000..f3a6ba8a657
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-move.rs
@@ -0,0 +1,33 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+// This function is not actually called, but is mentioned implicitly as destructor in dead code in a
+// function that is called. Make sure we still find this error.
+impl<T> Drop for Fail<T> {
+    fn drop(&mut self) {
+        let _ = Fail::<T>::C;
+    }
+}
+
+#[inline(never)]
+fn called<T>(x: T) {
+    if false {
+        let v = Fail(x);
+        drop(v); // move `v` away (and it then gets dropped there so build still fails)
+    }
+}
+
+pub fn main() {
+    called::<i32>(0);
+}
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
new file mode 100644
index 00000000000..6fd82777bd3
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/collect-in-dead-vtable.rs:12:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/collect-in-dead-vtable.rs:12:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: the above error was encountered while instantiating `fn <std::vec::Vec<i32> as MyTrait>::not_called`
+  --> $DIR/collect-in-dead-vtable.rs:35:40
+   |
+LL |         let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+   |                                        ^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/collect-in-dead-vtable.rs b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
new file mode 100644
index 00000000000..f21a1cc1fc2
--- /dev/null
+++ b/tests/ui/consts/required-consts/collect-in-dead-vtable.rs
@@ -0,0 +1,41 @@
+//@revisions: noopt opt
+//@[noopt] build-fail
+//@[opt] compile-flags: -O
+//FIXME: `opt` revision currently does not stop with an error due to
+//<https://github.com/rust-lang/rust/issues/107503>.
+//@[opt] build-pass
+//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is
+//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090)
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //[noopt]~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+trait MyTrait {
+    fn not_called(&self);
+}
+
+// This function is not actually called, but it is mentioned in a vtable in a function that is
+// called. Make sure we still find this error.
+// This relies on mono-item collection checking `required_consts` in functions that are referenced
+// in vtables that syntactically appear in collected functions (even inside dead code).
+impl<T> MyTrait for Vec<T> {
+    fn not_called(&self) {
+        if false {
+            let _ = Fail::<T>::C;
+        }
+    }
+}
+
+#[inline(never)]
+fn called<T>() {
+    if false {
+        let v: Vec<T> = Vec::new();
+        let gen_vtable: &dyn MyTrait = &v; // vtable "appears" here
+    }
+}
+
+pub fn main() {
+    called::<i32>();
+}
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
new file mode 100644
index 00000000000..75304591b9f
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-const-called-fn.rs:16:9
+   |
+LL |         Fail::<T>::C;
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
new file mode 100644
index 00000000000..75304591b9f
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.opt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-const-called-fn.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-const-called-fn.rs:16:9
+   |
+LL |         Fail::<T>::C;
+   |         ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const-eval/erroneous-const.rs b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
index 74d44c5259a..c409fae0bb9 100644
--- a/tests/ui/consts/const-eval/erroneous-const.rs
+++ b/tests/ui/consts/required-consts/interpret-in-const-called-fn.rs
@@ -1,16 +1,19 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
 //! Make sure we error on erroneous consts even if they are unused.
-#![allow(unconditional_panic)]
 
-struct PrintName<T>(T);
-impl<T> PrintName<T> {
-    const VOID: () = [()][2]; //~ERROR evaluation of `PrintName::<i32>::VOID` failed
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
 }
 
+#[inline(never)]
 const fn no_codegen<T>() {
     if false {
         // This bad constant is only used in dead code in a no-codegen function... and yet we still
         // must make sure that the build fails.
-            PrintName::<T>::VOID; //~ constant
+        // This relies on const-eval evaluating all `required_consts` of `const fn`.
+        Fail::<T>::C; //~ constant
     }
 }
 
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
new file mode 100644
index 00000000000..491131daf8d
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.noopt.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+   |
+   = note: entering unreachable code
+   |
+note: inside `unreachable_unchecked`
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+note: inside `ub`
+  --> $DIR/interpret-in-promoted.rs:6:5
+   |
+LL |     std::hint::unreachable_unchecked();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FOO`
+  --> $DIR/interpret-in-promoted.rs:12:28
+   |
+LL |     let _x: &'static () = &ub();
+   |                            ^^^^
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-promoted.rs:12:27
+   |
+LL |     let _x: &'static () = &ub();
+   |                           ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
new file mode 100644
index 00000000000..491131daf8d
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.opt.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+   |
+   = note: entering unreachable code
+   |
+note: inside `unreachable_unchecked`
+  --> $SRC_DIR/core/src/hint.rs:LL:COL
+note: inside `ub`
+  --> $DIR/interpret-in-promoted.rs:6:5
+   |
+LL |     std::hint::unreachable_unchecked();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: inside `FOO`
+  --> $DIR/interpret-in-promoted.rs:12:28
+   |
+LL |     let _x: &'static () = &ub();
+   |                            ^^^^
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-promoted.rs:12:27
+   |
+LL |     let _x: &'static () = &ub();
+   |                           ^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-promoted.rs b/tests/ui/consts/required-consts/interpret-in-promoted.rs
new file mode 100644
index 00000000000..9c2cf4e70d3
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-promoted.rs
@@ -0,0 +1,15 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
+//! Make sure we error on erroneous consts even if they are unused.
+
+const unsafe fn ub() {
+    std::hint::unreachable_unchecked();
+}
+
+pub const FOO: () = unsafe {
+    // Make sure that this gets promoted and then fails to evaluate, and we deal with that
+    // correctly.
+    let _x: &'static () = &ub(); //~ erroneous constant
+};
+
+fn main() {}
diff --git a/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
new file mode 100644
index 00000000000..159c9449fc0
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.noopt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-static.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-static.rs:15:9
+   |
+LL |         Fail::<i32>::C;
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-static.opt.stderr b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
new file mode 100644
index 00000000000..159c9449fc0
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.opt.stderr
@@ -0,0 +1,17 @@
+error[E0080]: evaluation of `Fail::<i32>::C` failed
+  --> $DIR/interpret-in-static.rs:7:19
+   |
+LL |     const C: () = panic!();
+   |                   ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/interpret-in-static.rs:7:19
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: erroneous constant encountered
+  --> $DIR/interpret-in-static.rs:15:9
+   |
+LL |         Fail::<i32>::C;
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/required-consts/interpret-in-static.rs b/tests/ui/consts/required-consts/interpret-in-static.rs
new file mode 100644
index 00000000000..559e281b2b0
--- /dev/null
+++ b/tests/ui/consts/required-consts/interpret-in-static.rs
@@ -0,0 +1,21 @@
+//@revisions: noopt opt
+//@[opt] compile-flags: -O
+//! Make sure we error on erroneous consts even if they are unused.
+
+struct Fail<T>(T);
+impl<T> Fail<T> {
+    const C: () = panic!(); //~ERROR evaluation of `Fail::<i32>::C` failed
+}
+
+pub static FOO: () = {
+    if false {
+        // This bad constant is only used in dead code in a static initializer... and yet we still
+        // must make sure that the build fails.
+        // This relies on const-eval evaluating all `required_consts` of the `static` MIR body.
+        Fail::<i32>::C; //~ constant
+    }
+};
+
+fn main() {
+    FOO
+}