about summary refs log tree commit diff
path: root/tests/ui/macros
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/macros')
-rw-r--r--tests/ui/macros/ambiguity-legacy-vs-modern.rs46
-rw-r--r--tests/ui/macros/ambiguity-legacy-vs-modern.stderr39
-rw-r--r--tests/ui/macros/assert-as-macro.rs7
-rw-r--r--tests/ui/macros/assert-eq-macro-msg.rs9
-rw-r--r--tests/ui/macros/assert-eq-macro-panic.rs9
-rw-r--r--tests/ui/macros/assert-eq-macro-success.rs13
-rw-r--r--tests/ui/macros/assert-eq-macro-unsized.rs4
-rw-r--r--tests/ui/macros/assert-format-lazy.rs12
-rw-r--r--tests/ui/macros/assert-macro-explicit.rs7
-rw-r--r--tests/ui/macros/assert-macro-fmt.rs7
-rw-r--r--tests/ui/macros/assert-macro-owned.rs9
-rw-r--r--tests/ui/macros/assert-macro-static.rs7
-rw-r--r--tests/ui/macros/assert-matches-macro-msg.rs13
-rw-r--r--tests/ui/macros/assert-ne-macro-msg.rs9
-rw-r--r--tests/ui/macros/assert-ne-macro-panic.rs9
-rw-r--r--tests/ui/macros/assert-ne-macro-success.rs13
-rw-r--r--tests/ui/macros/assert-ne-macro-unsized.rs4
-rw-r--r--tests/ui/macros/assert-trailing-junk.rs27
-rw-r--r--tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr58
-rw-r--r--tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr58
-rw-r--r--tests/ui/macros/assert.rs9
-rw-r--r--tests/ui/macros/assert.with-generic-asset.stderr28
-rw-r--r--tests/ui/macros/assert.without-generic-asset.stderr28
-rw-r--r--tests/ui/macros/attr-empty-expr.rs11
-rw-r--r--tests/ui/macros/attr-empty-expr.stderr20
-rw-r--r--tests/ui/macros/attr-from-macro.rs20
-rw-r--r--tests/ui/macros/auxiliary/attr-from-macro.rs15
-rw-r--r--tests/ui/macros/auxiliary/define-macro.rs6
-rw-r--r--tests/ui/macros/auxiliary/deprecated-macros.rs3
-rw-r--r--tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs10
-rw-r--r--tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs11
-rw-r--r--tests/ui/macros/auxiliary/issue-100199.rs18
-rw-r--r--tests/ui/macros/auxiliary/issue-19163.rs6
-rw-r--r--tests/ui/macros/auxiliary/issue-40469.rs1
-rw-r--r--tests/ui/macros/auxiliary/issue-75982.rs12
-rw-r--r--tests/ui/macros/auxiliary/macro-comma-support.rs1
-rw-r--r--tests/ui/macros/auxiliary/macro-def-site-super.rs13
-rw-r--r--tests/ui/macros/auxiliary/macro-in-other-crate.rs14
-rw-r--r--tests/ui/macros/auxiliary/macro-include-items-expr.rs3
-rw-r--r--tests/ui/macros/auxiliary/macro-include-items-item.rs3
-rw-r--r--tests/ui/macros/auxiliary/macro_crate_def_only.rs4
-rw-r--r--tests/ui/macros/auxiliary/macro_crate_nonterminal.rs12
-rw-r--r--tests/ui/macros/auxiliary/macro_export_inner_module.rs6
-rw-r--r--tests/ui/macros/auxiliary/macro_with_super_1.rs16
-rw-r--r--tests/ui/macros/auxiliary/or-pattern.rs6
-rw-r--r--tests/ui/macros/auxiliary/proc_macro_def.rs35
-rw-r--r--tests/ui/macros/auxiliary/proc_macro_sequence.rs27
-rw-r--r--tests/ui/macros/auxiliary/two_macros-rpass.rs5
-rw-r--r--tests/ui/macros/auxiliary/two_macros.rs5
-rw-r--r--tests/ui/macros/auxiliary/unstable-macros.rs16
-rw-r--r--tests/ui/macros/auxiliary/use-macro-self.rs6
-rw-r--r--tests/ui/macros/bad-concat.rs8
-rw-r--r--tests/ui/macros/bad-concat.stderr10
-rw-r--r--tests/ui/macros/bad_hello.rs6
-rw-r--r--tests/ui/macros/bad_hello.stderr24
-rw-r--r--tests/ui/macros/bang-after-name.fixed8
-rw-r--r--tests/ui/macros/bang-after-name.rs8
-rw-r--r--tests/ui/macros/bang-after-name.stderr8
-rw-r--r--tests/ui/macros/best-failure.rs11
-rw-r--r--tests/ui/macros/best-failure.stderr21
-rw-r--r--tests/ui/macros/builtin-prelude-no-accidents.rs8
-rw-r--r--tests/ui/macros/builtin-prelude-no-accidents.stderr21
-rw-r--r--tests/ui/macros/builtin-std-paths-fail.rs25
-rw-r--r--tests/ui/macros/builtin-std-paths-fail.stderr99
-rw-r--r--tests/ui/macros/builtin-std-paths.rs32
-rw-r--r--tests/ui/macros/cfg.rs6
-rw-r--r--tests/ui/macros/cfg.stderr31
-rw-r--r--tests/ui/macros/colorful-write-macros.rs34
-rw-r--r--tests/ui/macros/concat-bytes-error.rs50
-rw-r--r--tests/ui/macros/concat-bytes-error.stderr181
-rw-r--r--tests/ui/macros/concat-bytes.rs17
-rw-r--r--tests/ui/macros/concat-rpass.rs18
-rw-r--r--tests/ui/macros/concat.rs6
-rw-r--r--tests/ui/macros/concat.stderr30
-rw-r--r--tests/ui/macros/conditional-debug-macro-on.rs8
-rw-r--r--tests/ui/macros/cross-crate-pat-span.rs12
-rw-r--r--tests/ui/macros/derive-in-eager-expansion-hang.rs14
-rw-r--r--tests/ui/macros/derive-in-eager-expansion-hang.stderr22
-rw-r--r--tests/ui/macros/die-macro-2.rs7
-rw-r--r--tests/ui/macros/die-macro-expr.rs7
-rw-r--r--tests/ui/macros/die-macro-pure.rs11
-rw-r--r--tests/ui/macros/die-macro.rs16
-rw-r--r--tests/ui/macros/doc-comment.rs25
-rw-r--r--tests/ui/macros/dollar-crate-nested-encoding.rs8
-rw-r--r--tests/ui/macros/duplicate-builtin.rs17
-rw-r--r--tests/ui/macros/duplicate-builtin.stderr21
-rw-r--r--tests/ui/macros/edition-macro-pats.rs12
-rw-r--r--tests/ui/macros/empty-trailing-stmt.rs10
-rw-r--r--tests/ui/macros/empty-trailing-stmt.stderr22
-rw-r--r--tests/ui/macros/format-args-temporaries-async.rs37
-rw-r--r--tests/ui/macros/format-args-temporaries-in-write.rs50
-rw-r--r--tests/ui/macros/format-args-temporaries-in-write.stderr33
-rw-r--r--tests/ui/macros/format-args-temporaries.rs54
-rw-r--r--tests/ui/macros/format-foreign.rs17
-rw-r--r--tests/ui/macros/format-foreign.stderr82
-rw-r--r--tests/ui/macros/format-parse-errors.rs17
-rw-r--r--tests/ui/macros/format-parse-errors.stderr53
-rw-r--r--tests/ui/macros/format-unused-lables.rs18
-rw-r--r--tests/ui/macros/format-unused-lables.stderr50
-rw-r--r--tests/ui/macros/global-asm.rs7
-rw-r--r--tests/ui/macros/global-asm.stderr20
-rw-r--r--tests/ui/macros/html-literals.rs95
-rw-r--r--tests/ui/macros/include-single-expr-helper-1.rs5
-rw-r--r--tests/ui/macros/include-single-expr-helper.rs5
-rw-r--r--tests/ui/macros/include-single-expr.rs6
-rw-r--r--tests/ui/macros/include-single-expr.stderr10
-rw-r--r--tests/ui/macros/issue-100199.rs16
-rw-r--r--tests/ui/macros/issue-100199.stderr15
-rw-r--r--tests/ui/macros/issue-102878.rs10
-rw-r--r--tests/ui/macros/issue-102878.stderr60
-rw-r--r--tests/ui/macros/issue-103529.rs13
-rw-r--r--tests/ui/macros/issue-103529.stderr39
-rw-r--r--tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs8
-rw-r--r--tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr18
-rw-r--r--tests/ui/macros/issue-105011.rs3
-rw-r--r--tests/ui/macros/issue-105011.stderr8
-rw-r--r--tests/ui/macros/issue-10536.rs19
-rw-r--r--tests/ui/macros/issue-10536.stderr14
-rw-r--r--tests/ui/macros/issue-16098.rs16
-rw-r--r--tests/ui/macros/issue-16098.stderr14
-rw-r--r--tests/ui/macros/issue-19163.rs11
-rw-r--r--tests/ui/macros/issue-19163.stderr11
-rw-r--r--tests/ui/macros/issue-21356.rs6
-rw-r--r--tests/ui/macros/issue-21356.stderr10
-rw-r--r--tests/ui/macros/issue-22463.rs20
-rw-r--r--tests/ui/macros/issue-25274.rs18
-rw-r--r--tests/ui/macros/issue-25385.rs12
-rw-r--r--tests/ui/macros/issue-25385.stderr20
-rw-r--r--tests/ui/macros/issue-26322.rs30
-rw-r--r--tests/ui/macros/issue-29084.rs13
-rw-r--r--tests/ui/macros/issue-29084.stderr24
-rw-r--r--tests/ui/macros/issue-30143.rs11
-rw-r--r--tests/ui/macros/issue-30143.stderr35
-rw-r--r--tests/ui/macros/issue-33185.rs17
-rw-r--r--tests/ui/macros/issue-34171.rs10
-rw-r--r--tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs15
-rw-r--r--tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr34
-rw-r--r--tests/ui/macros/issue-35450.rs5
-rw-r--r--tests/ui/macros/issue-35450.stderr8
-rw-r--r--tests/ui/macros/issue-37175.rs5
-rw-r--r--tests/ui/macros/issue-38715.rs17
-rw-r--r--tests/ui/macros/issue-38715.stderr25
-rw-r--r--tests/ui/macros/issue-39388.rs9
-rw-r--r--tests/ui/macros/issue-39388.stderr8
-rw-r--r--tests/ui/macros/issue-39404.rs7
-rw-r--r--tests/ui/macros/issue-39404.stderr12
-rw-r--r--tests/ui/macros/issue-40469.rs9
-rw-r--r--tests/ui/macros/issue-40770.rs11
-rw-r--r--tests/ui/macros/issue-41776.rs3
-rw-r--r--tests/ui/macros/issue-41776.stderr8
-rw-r--r--tests/ui/macros/issue-41803.rs23
-rw-r--r--tests/ui/macros/issue-42954.fixed14
-rw-r--r--tests/ui/macros/issue-42954.rs14
-rw-r--r--tests/ui/macros/issue-42954.stderr19
-rw-r--r--tests/ui/macros/issue-44127.rs17
-rw-r--r--tests/ui/macros/issue-5060.rs16
-rw-r--r--tests/ui/macros/issue-51848.rs20
-rw-r--r--tests/ui/macros/issue-51848.stderr24
-rw-r--r--tests/ui/macros/issue-52169.rs15
-rw-r--r--tests/ui/macros/issue-54441.rs11
-rw-r--r--tests/ui/macros/issue-54441.stderr13
-rw-r--r--tests/ui/macros/issue-57597.rs80
-rw-r--r--tests/ui/macros/issue-57597.stderr74
-rw-r--r--tests/ui/macros/issue-58490.rs26
-rw-r--r--tests/ui/macros/issue-58490.stderr14
-rw-r--r--tests/ui/macros/issue-61033-1.rs10
-rw-r--r--tests/ui/macros/issue-61033-1.stderr17
-rw-r--r--tests/ui/macros/issue-61033-2.rs25
-rw-r--r--tests/ui/macros/issue-61033-2.stderr24
-rw-r--r--tests/ui/macros/issue-61053-different-kleene.rs30
-rw-r--r--tests/ui/macros/issue-61053-different-kleene.stderr45
-rw-r--r--tests/ui/macros/issue-61053-duplicate-binder.rs14
-rw-r--r--tests/ui/macros/issue-61053-duplicate-binder.stderr16
-rw-r--r--tests/ui/macros/issue-61053-missing-repetition.rs28
-rw-r--r--tests/ui/macros/issue-61053-missing-repetition.stderr33
-rw-r--r--tests/ui/macros/issue-61053-unbound.rs28
-rw-r--r--tests/ui/macros/issue-61053-unbound.stderr26
-rw-r--r--tests/ui/macros/issue-63102.rs8
-rw-r--r--tests/ui/macros/issue-6596-1.rs10
-rw-r--r--tests/ui/macros/issue-6596-1.stderr13
-rw-r--r--tests/ui/macros/issue-68058.rs14
-rw-r--r--tests/ui/macros/issue-68060.rs15
-rw-r--r--tests/ui/macros/issue-68060.stderr27
-rw-r--r--tests/ui/macros/issue-69838-dir/bar.rs3
-rw-r--r--tests/ui/macros/issue-69838-dir/included.rs3
-rw-r--r--tests/ui/macros/issue-69838-mods-relative-to-included-path.rs7
-rw-r--r--tests/ui/macros/issue-70446.rs13
-rw-r--r--tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs13
-rw-r--r--tests/ui/macros/issue-77475.rs10
-rw-r--r--tests/ui/macros/issue-78325-inconsistent-resolution.rs12
-rw-r--r--tests/ui/macros/issue-78325-inconsistent-resolution.stderr13
-rw-r--r--tests/ui/macros/issue-78333.rs13
-rw-r--r--tests/ui/macros/issue-78892-substitution-in-statement-attr.rs14
-rw-r--r--tests/ui/macros/issue-81006.rs10
-rw-r--r--tests/ui/macros/issue-81006.stderr14
-rw-r--r--tests/ui/macros/issue-83340.rs8
-rw-r--r--tests/ui/macros/issue-83340.stderr8
-rw-r--r--tests/ui/macros/issue-83344.rs6
-rw-r--r--tests/ui/macros/issue-83344.stderr8
-rw-r--r--tests/ui/macros/issue-84195-lint-anon-const.rs14
-rw-r--r--tests/ui/macros/issue-84195-lint-anon-const.stderr20
-rw-r--r--tests/ui/macros/issue-84429-matches-edition.rs9
-rw-r--r--tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs16
-rw-r--r--tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr14
-rw-r--r--tests/ui/macros/issue-86082-option-env-invalid-char.rs10
-rw-r--r--tests/ui/macros/issue-86865.rs11
-rw-r--r--tests/ui/macros/issue-86865.stderr18
-rw-r--r--tests/ui/macros/issue-8709.rs14
-rw-r--r--tests/ui/macros/issue-87877.rs25
-rw-r--r--tests/ui/macros/issue-88206.rs66
-rw-r--r--tests/ui/macros/issue-88206.stderr114
-rw-r--r--tests/ui/macros/issue-88228.rs23
-rw-r--r--tests/ui/macros/issue-88228.stderr28
-rw-r--r--tests/ui/macros/issue-8851.rs30
-rw-r--r--tests/ui/macros/issue-92267.rs3
-rw-r--r--tests/ui/macros/issue-92267.stderr16
-rw-r--r--tests/ui/macros/issue-95267.rs14
-rw-r--r--tests/ui/macros/issue-95533.rs8
-rw-r--r--tests/ui/macros/issue-98466-allow.rs16
-rw-r--r--tests/ui/macros/issue-98466.fixed51
-rw-r--r--tests/ui/macros/issue-98466.rs51
-rw-r--r--tests/ui/macros/issue-98466.stderr81
-rw-r--r--tests/ui/macros/issue-99261.rs17
-rw-r--r--tests/ui/macros/issue-99265.fixed139
-rw-r--r--tests/ui/macros/issue-99265.rs139
-rw-r--r--tests/ui/macros/issue-99265.stderr562
-rw-r--r--tests/ui/macros/issue-99907.fixed24
-rw-r--r--tests/ui/macros/issue-99907.rs24
-rw-r--r--tests/ui/macros/issue-99907.stderr68
-rw-r--r--tests/ui/macros/lint-trailing-macro-call.rs16
-rw-r--r--tests/ui/macros/lint-trailing-macro-call.stderr18
-rw-r--r--tests/ui/macros/local-ambiguity-multiple-parsing-options.rs8
-rw-r--r--tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr14
-rw-r--r--tests/ui/macros/log_syntax-trace_macros-macro-locations.rs22
-rw-r--r--tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout3
-rw-r--r--tests/ui/macros/macro-2.rs12
-rw-r--r--tests/ui/macros/macro-as-fn-body.rs33
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs50
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.rs42
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.stderr161
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs50
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.rs42
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.stderr161
-rw-r--r--tests/ui/macros/macro-attribute-expansion.rs16
-rw-r--r--tests/ui/macros/macro-attribute.rs2
-rw-r--r--tests/ui/macros/macro-attribute.stderr8
-rw-r--r--tests/ui/macros/macro-attributes.rs23
-rw-r--r--tests/ui/macros/macro-backtrace-invalid-internals.rs61
-rw-r--r--tests/ui/macros/macro-backtrace-invalid-internals.stderr100
-rw-r--r--tests/ui/macros/macro-backtrace-nested.rs20
-rw-r--r--tests/ui/macros/macro-backtrace-nested.stderr25
-rw-r--r--tests/ui/macros/macro-backtrace-println.rs19
-rw-r--r--tests/ui/macros/macro-backtrace-println.stderr13
-rw-r--r--tests/ui/macros/macro-block-nonterminal.rs11
-rw-r--r--tests/ui/macros/macro-comma-behavior-rpass.rs98
-rw-r--r--tests/ui/macros/macro-comma-behavior.core.stderr50
-rw-r--r--tests/ui/macros/macro-comma-behavior.rs89
-rw-r--r--tests/ui/macros/macro-comma-behavior.std.stderr80
-rw-r--r--tests/ui/macros/macro-comma-support-rpass.rs355
-rw-r--r--tests/ui/macros/macro-comma-support.rs10
-rw-r--r--tests/ui/macros/macro-comma-support.stderr14
-rw-r--r--tests/ui/macros/macro-context.rs21
-rw-r--r--tests/ui/macros/macro-context.stderr84
-rw-r--r--tests/ui/macros/macro-crate-def-only.rs10
-rw-r--r--tests/ui/macros/macro-crate-nonterminal-non-root.rs9
-rw-r--r--tests/ui/macros/macro-crate-nonterminal-non-root.stderr9
-rw-r--r--tests/ui/macros/macro-crate-nonterminal-renamed.rs10
-rw-r--r--tests/ui/macros/macro-crate-nonterminal.rs10
-rw-r--r--tests/ui/macros/macro-crate-use.rs17
-rw-r--r--tests/ui/macros/macro-deep_expansion.rs17
-rw-r--r--tests/ui/macros/macro-def-site-super.rs10
-rw-r--r--tests/ui/macros/macro-delimiter-significance.rs4
-rw-r--r--tests/ui/macros/macro-deprecation.rs13
-rw-r--r--tests/ui/macros/macro-deprecation.stderr16
-rw-r--r--tests/ui/macros/macro-doc-comments.rs26
-rw-r--r--tests/ui/macros/macro-doc-escapes.rs16
-rw-r--r--tests/ui/macros/macro-doc-raw-str-hashes.rs30
-rw-r--r--tests/ui/macros/macro-error.rs9
-rw-r--r--tests/ui/macros/macro-error.stderr14
-rw-r--r--tests/ui/macros/macro-expanded-include/file.txt0
-rw-r--r--tests/ui/macros/macro-expanded-include/foo/mod.rs9
-rw-r--r--tests/ui/macros/macro-expanded-include/test.rs13
-rw-r--r--tests/ui/macros/macro-expansion-tests.rs40
-rw-r--r--tests/ui/macros/macro-expansion-tests.stderr18
-rw-r--r--tests/ui/macros/macro-export-inner-module.rs9
-rw-r--r--tests/ui/macros/macro-first-set.rs272
-rw-r--r--tests/ui/macros/macro-follow-rpass.rs183
-rw-r--r--tests/ui/macros/macro-follow.rs114
-rw-r--r--tests/ui/macros/macro-follow.stderr682
-rw-r--r--tests/ui/macros/macro-followed-by-seq-bad.rs11
-rw-r--r--tests/ui/macros/macro-followed-by-seq-bad.stderr18
-rw-r--r--tests/ui/macros/macro-followed-by-seq.rs14
-rw-r--r--tests/ui/macros/macro-in-expression-context-2.rs8
-rw-r--r--tests/ui/macros/macro-in-expression-context-2.stderr17
-rw-r--r--tests/ui/macros/macro-in-expression-context.fixed27
-rw-r--r--tests/ui/macros/macro-in-expression-context.rs27
-rw-r--r--tests/ui/macros/macro-in-expression-context.stderr33
-rw-r--r--tests/ui/macros/macro-in-fn.rs8
-rw-r--r--tests/ui/macros/macro-include-items.rs13
-rw-r--r--tests/ui/macros/macro-inner-attributes.rs20
-rw-r--r--tests/ui/macros/macro-inner-attributes.stderr14
-rw-r--r--tests/ui/macros/macro-input-future-proofing.rs23
-rw-r--r--tests/ui/macros/macro-input-future-proofing.stderr74
-rw-r--r--tests/ui/macros/macro-interpolation.rs33
-rw-r--r--tests/ui/macros/macro-invalid-fragment-spec.rs8
-rw-r--r--tests/ui/macros/macro-invalid-fragment-spec.stderr10
-rw-r--r--tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs10
-rw-r--r--tests/ui/macros/macro-lifetime-used-with-bound.rs15
-rw-r--r--tests/ui/macros/macro-lifetime-used-with-labels.rs36
-rw-r--r--tests/ui/macros/macro-lifetime-used-with-static.rs14
-rw-r--r--tests/ui/macros/macro-lifetime.rs14
-rw-r--r--tests/ui/macros/macro-literal.rs134
-rw-r--r--tests/ui/macros/macro-local-data-key-priv.rs10
-rw-r--r--tests/ui/macros/macro-local-data-key-priv.stderr16
-rw-r--r--tests/ui/macros/macro-match-nonterminal.rs14
-rw-r--r--tests/ui/macros/macro-match-nonterminal.stderr27
-rw-r--r--tests/ui/macros/macro-meta-items-modern.rs11
-rw-r--r--tests/ui/macros/macro-meta-items.rs31
-rw-r--r--tests/ui/macros/macro-method-issue-4621.rs10
-rw-r--r--tests/ui/macros/macro-missing-delimiters.rs7
-rw-r--r--tests/ui/macros/macro-missing-delimiters.stderr8
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.rs15
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.stderr18
-rw-r--r--tests/ui/macros/macro-missing-fragment.rs26
-rw-r--r--tests/ui/macros/macro-missing-fragment.stderr40
-rw-r--r--tests/ui/macros/macro-multiple-items.rs16
-rw-r--r--tests/ui/macros/macro-multiple-matcher-bindings.rs21
-rw-r--r--tests/ui/macros/macro-multiple-matcher-bindings.stderr34
-rw-r--r--tests/ui/macros/macro-name-typo.rs3
-rw-r--r--tests/ui/macros/macro-name-typo.stderr11
-rw-r--r--tests/ui/macros/macro-named-default.rs18
-rw-r--r--tests/ui/macros/macro-nested_definition_issue-31946.rs9
-rw-r--r--tests/ui/macros/macro-nested_expr.rs22
-rw-r--r--tests/ui/macros/macro-nested_stmt_macros.rs23
-rw-r--r--tests/ui/macros/macro-non-lifetime.rs8
-rw-r--r--tests/ui/macros/macro-non-lifetime.stderr17
-rw-r--r--tests/ui/macros/macro-nt-list.rs21
-rw-r--r--tests/ui/macros/macro-of-higher-order.rs22
-rw-r--r--tests/ui/macros/macro-or-patterns-back-compat.fixed39
-rw-r--r--tests/ui/macros/macro-or-patterns-back-compat.rs39
-rw-r--r--tests/ui/macros/macro-or-patterns-back-compat.stderr43
-rw-r--r--tests/ui/macros/macro-outer-attributes.rs20
-rw-r--r--tests/ui/macros/macro-outer-attributes.stderr19
-rw-r--r--tests/ui/macros/macro-parameter-span.rs13
-rw-r--r--tests/ui/macros/macro-parameter-span.stderr9
-rw-r--r--tests/ui/macros/macro-pat-follow-2018.rs15
-rw-r--r--tests/ui/macros/macro-pat-follow.rs21
-rw-r--r--tests/ui/macros/macro-pat-neg-lit.rs25
-rw-r--r--tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs20
-rw-r--r--tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr32
-rw-r--r--tests/ui/macros/macro-pat-pattern-followed-by-or.rs20
-rw-r--r--tests/ui/macros/macro-pat.rs65
-rw-r--r--tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs22
-rw-r--r--tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr32
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-1.rs8
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-1.stderr15
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-2.rs7
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-2.stderr9
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-3.rs3
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-3.stderr13
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-4.rs4
-rw-r--r--tests/ui/macros/macro-path-prelude-fail-4.stderr8
-rw-r--r--tests/ui/macros/macro-path-prelude-pass.rs9
-rw-r--r--tests/ui/macros/macro-path-prelude-shadowing.rs33
-rw-r--r--tests/ui/macros/macro-path-prelude-shadowing.stderr19
-rw-r--r--tests/ui/macros/macro-path.rs18
-rw-r--r--tests/ui/macros/macro-pub-matcher.rs117
-rw-r--r--tests/ui/macros/macro-reexport-removed.rs8
-rw-r--r--tests/ui/macros/macro-reexport-removed.stderr17
-rw-r--r--tests/ui/macros/macro-seq-followed-by-seq.rs17
-rw-r--r--tests/ui/macros/macro-shadowing-relaxed.rs25
-rw-r--r--tests/ui/macros/macro-shadowing.rs26
-rw-r--r--tests/ui/macros/macro-shadowing.stderr37
-rw-r--r--tests/ui/macros/macro-stability-rpass.rs15
-rw-r--r--tests/ui/macros/macro-stability.rs31
-rw-r--r--tests/ui/macros/macro-stability.stderr41
-rw-r--r--tests/ui/macros/macro-stmt-matchers.rs7
-rw-r--r--tests/ui/macros/macro-stmt.rs31
-rw-r--r--tests/ui/macros/macro-stmt_macro_in_expr_macro.rs21
-rw-r--r--tests/ui/macros/macro-tt-followed-by-seq.rs28
-rw-r--r--tests/ui/macros/macro-tt-matchers.rs11
-rw-r--r--tests/ui/macros/macro-use-all-and-none.rs13
-rw-r--r--tests/ui/macros/macro-use-all-and-none.stderr15
-rw-r--r--tests/ui/macros/macro-use-all.rs10
-rw-r--r--tests/ui/macros/macro-use-bad-args-1.rs6
-rw-r--r--tests/ui/macros/macro-use-bad-args-1.stderr9
-rw-r--r--tests/ui/macros/macro-use-bad-args-2.rs6
-rw-r--r--tests/ui/macros/macro-use-bad-args-2.stderr9
-rw-r--r--tests/ui/macros/macro-use-both.rs10
-rw-r--r--tests/ui/macros/macro-use-one.rs9
-rw-r--r--tests/ui/macros/macro-use-scope.rs22
-rw-r--r--tests/ui/macros/macro-use-undef.rs8
-rw-r--r--tests/ui/macros/macro-use-undef.stderr9
-rw-r--r--tests/ui/macros/macro-use-wrong-name.rs9
-rw-r--r--tests/ui/macros/macro-use-wrong-name.stderr16
-rw-r--r--tests/ui/macros/macro-with-attrs1.rs13
-rw-r--r--tests/ui/macros/macro-with-attrs2.rs11
-rw-r--r--tests/ui/macros/macro-with-braces-in-expr-position.rs22
-rw-r--r--tests/ui/macros/macro_path_as_generic_bound.rs9
-rw-r--r--tests/ui/macros/macro_path_as_generic_bound.stderr9
-rw-r--r--tests/ui/macros/macro_rules-unmatchable-literals.rs14
-rw-r--r--tests/ui/macros/macro_rules-unmatchable-literals.stderr14
-rw-r--r--tests/ui/macros/macro_undefined.rs13
-rw-r--r--tests/ui/macros/macro_undefined.stderr11
-rw-r--r--tests/ui/macros/macro_with_super_2.rs13
-rw-r--r--tests/ui/macros/macros-in-extern.rs51
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.rs139
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.stderr235
-rw-r--r--tests/ui/macros/malformed_macro_lhs.rs7
-rw-r--r--tests/ui/macros/malformed_macro_lhs.stderr8
-rw-r--r--tests/ui/macros/meta-item-absolute-path.rs5
-rw-r--r--tests/ui/macros/meta-item-absolute-path.stderr15
-rw-r--r--tests/ui/macros/meta-variable-depth-outside-repeat.rs12
-rw-r--r--tests/ui/macros/meta-variable-depth-outside-repeat.stderr8
-rw-r--r--tests/ui/macros/meta-variable-misuse.rs34
-rw-r--r--tests/ui/macros/missing-bang-in-decl.fixed16
-rw-r--r--tests/ui/macros/missing-bang-in-decl.rs16
-rw-r--r--tests/ui/macros/missing-bang-in-decl.stderr20
-rw-r--r--tests/ui/macros/missing-comma.rs34
-rw-r--r--tests/ui/macros/missing-comma.stderr104
-rw-r--r--tests/ui/macros/must-use-in-macro-55516.rs10
-rw-r--r--tests/ui/macros/must-use-in-macro-55516.stderr12
-rw-r--r--tests/ui/macros/no-std-macros.rs13
-rw-r--r--tests/ui/macros/none-delim-lookahead.rs15
-rw-r--r--tests/ui/macros/nonterminal-matching.rs26
-rw-r--r--tests/ui/macros/nonterminal-matching.stderr24
-rw-r--r--tests/ui/macros/not-utf8.binbin0 -> 3036 bytes
-rw-r--r--tests/ui/macros/not-utf8.rs5
-rw-r--r--tests/ui/macros/not-utf8.stderr10
-rw-r--r--tests/ui/macros/out-of-order-shadowing.rs10
-rw-r--r--tests/ui/macros/out-of-order-shadowing.stderr22
-rw-r--r--tests/ui/macros/parse-complex-macro-invoc-op.rs42
-rw-r--r--tests/ui/macros/paths-in-macro-invocations.rs36
-rw-r--r--tests/ui/macros/proc_macro.rs37
-rw-r--r--tests/ui/macros/pub-item-inside-macro.rs18
-rw-r--r--tests/ui/macros/pub-method-inside-macro.rs22
-rw-r--r--tests/ui/macros/recovery-allowed.rs8
-rw-r--r--tests/ui/macros/recovery-allowed.stderr10
-rw-r--r--tests/ui/macros/recovery-forbidden.rs13
-rw-r--r--tests/ui/macros/restricted-shadowing-legacy.rs289
-rw-r--r--tests/ui/macros/restricted-shadowing-legacy.stderr227
-rw-r--r--tests/ui/macros/restricted-shadowing-modern.rs241
-rw-r--r--tests/ui/macros/restricted-shadowing-modern.stderr171
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs186
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs44
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs13
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs15
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs25
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs26
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs32
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout147
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs271
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs28
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs148
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs102
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs43
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr20
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs44
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr93
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs165
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr385
-rw-r--r--tests/ui/macros/same-sequence-span.rs22
-rw-r--r--tests/ui/macros/same-sequence-span.stderr43
-rw-r--r--tests/ui/macros/semi-after-macro-ty.rs8
-rw-r--r--tests/ui/macros/span-covering-argument-1.rs13
-rw-r--r--tests/ui/macros/span-covering-argument-1.stderr18
-rw-r--r--tests/ui/macros/stmt_expr_attr_macro_parse.rs25
-rw-r--r--tests/ui/macros/stringify.rs889
-rw-r--r--tests/ui/macros/syntax-error-recovery.rs18
-rw-r--r--tests/ui/macros/syntax-error-recovery.stderr31
-rw-r--r--tests/ui/macros/syntax-extension-cfg.rs24
-rw-r--r--tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment7
-rw-r--r--tests/ui/macros/syntax-extension-source-utils.rs37
-rw-r--r--tests/ui/macros/trace-macro.rs6
-rw-r--r--tests/ui/macros/trace-macro.stderr9
-rw-r--r--tests/ui/macros/trace_faulty_macros.rs43
-rw-r--r--tests/ui/macros/trace_faulty_macros.stderr85
-rw-r--r--tests/ui/macros/trace_macros-format.rs18
-rw-r--r--tests/ui/macros/trace_macros-format.stderr38
-rw-r--r--tests/ui/macros/try-macro.rs49
-rw-r--r--tests/ui/macros/two-macro-use.rs11
-rw-r--r--tests/ui/macros/type-macros-hlist.rs80
-rw-r--r--tests/ui/macros/type-macros-simple.rs30
-rw-r--r--tests/ui/macros/typeck-macro-interaction-issue-8852.rs30
-rw-r--r--tests/ui/macros/unimplemented-macro-panic.rs7
-rw-r--r--tests/ui/macros/unknown-builtin.rs14
-rw-r--r--tests/ui/macros/unknown-builtin.stderr18
-rw-r--r--tests/ui/macros/unreachable-arg.edition_2021.stderr13
-rw-r--r--tests/ui/macros/unreachable-arg.rs16
-rw-r--r--tests/ui/macros/unreachable-fmt-msg.rs7
-rw-r--r--tests/ui/macros/unreachable-format-arg.rs15
-rw-r--r--tests/ui/macros/unreachable-format-args.edition_2015.stderr12
-rw-r--r--tests/ui/macros/unreachable-format-args.rs14
-rw-r--r--tests/ui/macros/unreachable-macro-panic.rs7
-rw-r--r--tests/ui/macros/unreachable-static-msg.rs7
-rw-r--r--tests/ui/macros/unreachable.rs7
-rw-r--r--tests/ui/macros/use-macro-self.rs12
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.rs10
-rw-r--r--tests/ui/macros/vec-macro-in-pattern.stderr10
499 files changed, 16460 insertions, 0 deletions
diff --git a/tests/ui/macros/ambiguity-legacy-vs-modern.rs b/tests/ui/macros/ambiguity-legacy-vs-modern.rs
new file mode 100644
index 00000000000..216b9dd0526
--- /dev/null
+++ b/tests/ui/macros/ambiguity-legacy-vs-modern.rs
@@ -0,0 +1,46 @@
+// Some non-controversial subset of ambiguities "modern macro name" vs "macro_rules"
+// is disambiguated to mitigate regressions from macro modularization.
+// Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
+
+#![feature(decl_macro)]
+
+fn same_unnamed_mod() {
+    macro m() { 0 }
+
+    macro_rules! m { () => (()) }
+
+    m!() // OK
+}
+
+fn nested_unnamed_mod() {
+    macro m() { 0 }
+
+    {
+        macro_rules! m { () => (()) }
+
+        m!() // OK
+    }
+}
+
+fn nested_unnamed_mod_fail() {
+    macro_rules! m { () => (()) }
+
+    {
+        macro m() { 0 }
+
+        m!() //~ ERROR `m` is ambiguous
+    }
+}
+
+fn nexted_named_mod_fail() {
+    macro m() { 0 }
+
+    #[macro_use]
+    mod inner {
+        macro_rules! m { () => (()) }
+    }
+
+    m!() //~ ERROR `m` is ambiguous
+}
+
+fn main() {}
diff --git a/tests/ui/macros/ambiguity-legacy-vs-modern.stderr b/tests/ui/macros/ambiguity-legacy-vs-modern.stderr
new file mode 100644
index 00000000000..330aa6acf35
--- /dev/null
+++ b/tests/ui/macros/ambiguity-legacy-vs-modern.stderr
@@ -0,0 +1,39 @@
+error[E0659]: `m` is ambiguous
+  --> $DIR/ambiguity-legacy-vs-modern.rs:31:9
+   |
+LL |         m!()
+   |         ^ ambiguous name
+   |
+   = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
+note: `m` could refer to the macro defined here
+  --> $DIR/ambiguity-legacy-vs-modern.rs:26:5
+   |
+LL |     macro_rules! m { () => (()) }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `m` could also refer to the macro defined here
+  --> $DIR/ambiguity-legacy-vs-modern.rs:29:9
+   |
+LL |         macro m() { 0 }
+   |         ^^^^^^^^^^^^^^^
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/ambiguity-legacy-vs-modern.rs:43:5
+   |
+LL |     m!()
+   |     ^ ambiguous name
+   |
+   = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
+note: `m` could refer to the macro defined here
+  --> $DIR/ambiguity-legacy-vs-modern.rs:40:9
+   |
+LL |         macro_rules! m { () => (()) }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: `m` could also refer to the macro defined here
+  --> $DIR/ambiguity-legacy-vs-modern.rs:36:5
+   |
+LL |     macro m() { 0 }
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/assert-as-macro.rs b/tests/ui/macros/assert-as-macro.rs
new file mode 100644
index 00000000000..23c05480813
--- /dev/null
+++ b/tests/ui/macros/assert-as-macro.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:assertion failed: 1 == 2
+// ignore-emscripten no processes
+
+fn main() {
+    assert!(1 == 2);
+}
diff --git a/tests/ui/macros/assert-eq-macro-msg.rs b/tests/ui/macros/assert-eq-macro-msg.rs
new file mode 100644
index 00000000000..accbd2d1e7f
--- /dev/null
+++ b/tests/ui/macros/assert-eq-macro-msg.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:panicked at 'assertion failed: `(left == right)`
+// error-pattern: left: `2`
+// error-pattern:right: `3`: 1 + 1 definitely should be 3'
+// ignore-emscripten no processes
+
+fn main() {
+    assert_eq!(1 + 1, 3, "1 + 1 definitely should be 3");
+}
diff --git a/tests/ui/macros/assert-eq-macro-panic.rs b/tests/ui/macros/assert-eq-macro-panic.rs
new file mode 100644
index 00000000000..5e505c30b35
--- /dev/null
+++ b/tests/ui/macros/assert-eq-macro-panic.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:assertion failed: `(left == right)`
+// error-pattern: left: `14`
+// error-pattern:right: `15`
+// ignore-emscripten no processes
+
+fn main() {
+    assert_eq!(14, 15);
+}
diff --git a/tests/ui/macros/assert-eq-macro-success.rs b/tests/ui/macros/assert-eq-macro-success.rs
new file mode 100644
index 00000000000..57858b34837
--- /dev/null
+++ b/tests/ui/macros/assert-eq-macro-success.rs
@@ -0,0 +1,13 @@
+// run-pass
+#[derive(PartialEq, Debug)]
+struct Point { x : isize }
+
+pub fn main() {
+    assert_eq!(14,14);
+    assert_eq!("abc".to_string(),"abc".to_string());
+    assert_eq!(Box::new(Point{x:34}),Box::new(Point{x:34}));
+    assert_eq!(&Point{x:34},&Point{x:34});
+    assert_eq!(42, 42, "foo bar");
+    assert_eq!(42, 42, "a {} c", "b");
+    assert_eq!(42, 42, "{x}, {y}, {z}", x = 1, y = 2, z = 3);
+}
diff --git a/tests/ui/macros/assert-eq-macro-unsized.rs b/tests/ui/macros/assert-eq-macro-unsized.rs
new file mode 100644
index 00000000000..00823216bf6
--- /dev/null
+++ b/tests/ui/macros/assert-eq-macro-unsized.rs
@@ -0,0 +1,4 @@
+// run-pass
+pub fn main() {
+    assert_eq!([1, 2, 3][..], vec![1, 2, 3][..]);
+}
diff --git a/tests/ui/macros/assert-format-lazy.rs b/tests/ui/macros/assert-format-lazy.rs
new file mode 100644
index 00000000000..c7f05d763b7
--- /dev/null
+++ b/tests/ui/macros/assert-format-lazy.rs
@@ -0,0 +1,12 @@
+// run-pass
+// compile-flags: -C debug_assertions=yes
+
+#[allow(unreachable_code)]
+fn main() {
+    assert!(true, "Failed: {:?}", panic!("assert! evaluated format expressions"));
+    debug_assert!(true, "Failed: {:?}", panic!("debug_assert! evaluated format expressions"));
+    assert_eq!(1, 1, "Failed: {:?}", panic!("assert_eq! evaluated format expressions"));
+    debug_assert_eq!(1, 1, "Failed: {:?}", panic!("debug_assert_eq! evaluated format expressions"));
+    assert_ne!(1, 2, "Failed: {:?}", panic!("assert_ne! evaluated format expressions"));
+    debug_assert_ne!(1, 2, "Failed: {:?}", panic!("debug_assert_ne! evaluated format expressions"));
+}
diff --git a/tests/ui/macros/assert-macro-explicit.rs b/tests/ui/macros/assert-macro-explicit.rs
new file mode 100644
index 00000000000..578ef563278
--- /dev/null
+++ b/tests/ui/macros/assert-macro-explicit.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:panicked at 'assertion failed: false'
+// ignore-emscripten no processes
+
+fn main() {
+    assert!(false);
+}
diff --git a/tests/ui/macros/assert-macro-fmt.rs b/tests/ui/macros/assert-macro-fmt.rs
new file mode 100644
index 00000000000..b8d319d85f4
--- /dev/null
+++ b/tests/ui/macros/assert-macro-fmt.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:panicked at 'test-assert-fmt 42 rust'
+// ignore-emscripten no processes
+
+fn main() {
+    assert!(false, "test-assert-fmt {} {}", 42, "rust");
+}
diff --git a/tests/ui/macros/assert-macro-owned.rs b/tests/ui/macros/assert-macro-owned.rs
new file mode 100644
index 00000000000..753675872b9
--- /dev/null
+++ b/tests/ui/macros/assert-macro-owned.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:panicked at 'test-assert-owned'
+// ignore-emscripten no processes
+
+#![allow(non_fmt_panics)]
+
+fn main() {
+    assert!(false, "test-assert-owned".to_string());
+}
diff --git a/tests/ui/macros/assert-macro-static.rs b/tests/ui/macros/assert-macro-static.rs
new file mode 100644
index 00000000000..dc5274a7e88
--- /dev/null
+++ b/tests/ui/macros/assert-macro-static.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:panicked at 'test-assert-static'
+// ignore-emscripten no processes
+
+fn main() {
+    assert!(false, "test-assert-static");
+}
diff --git a/tests/ui/macros/assert-matches-macro-msg.rs b/tests/ui/macros/assert-matches-macro-msg.rs
new file mode 100644
index 00000000000..fd8cd5a1a05
--- /dev/null
+++ b/tests/ui/macros/assert-matches-macro-msg.rs
@@ -0,0 +1,13 @@
+// run-fail
+// error-pattern:panicked at 'assertion failed: `(left matches right)`
+// error-pattern: left: `2`
+// error-pattern:right: `3`: 1 + 1 definitely should be 3'
+// ignore-emscripten no processes
+
+#![feature(assert_matches)]
+
+use std::assert_matches::assert_matches;
+
+fn main() {
+    assert_matches!(1 + 1, 3, "1 + 1 definitely should be 3");
+}
diff --git a/tests/ui/macros/assert-ne-macro-msg.rs b/tests/ui/macros/assert-ne-macro-msg.rs
new file mode 100644
index 00000000000..fc0472b99b4
--- /dev/null
+++ b/tests/ui/macros/assert-ne-macro-msg.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:panicked at 'assertion failed: `(left != right)`
+// error-pattern: left: `2`
+// error-pattern:right: `2`: 1 + 1 definitely should not be 2'
+// ignore-emscripten no processes
+
+fn main() {
+    assert_ne!(1 + 1, 2, "1 + 1 definitely should not be 2");
+}
diff --git a/tests/ui/macros/assert-ne-macro-panic.rs b/tests/ui/macros/assert-ne-macro-panic.rs
new file mode 100644
index 00000000000..4f507d7b54d
--- /dev/null
+++ b/tests/ui/macros/assert-ne-macro-panic.rs
@@ -0,0 +1,9 @@
+// run-fail
+// error-pattern:assertion failed: `(left != right)`
+// error-pattern: left: `14`
+// error-pattern:right: `14`
+// ignore-emscripten no processes
+
+fn main() {
+    assert_ne!(14, 14);
+}
diff --git a/tests/ui/macros/assert-ne-macro-success.rs b/tests/ui/macros/assert-ne-macro-success.rs
new file mode 100644
index 00000000000..89b3a4c9d6a
--- /dev/null
+++ b/tests/ui/macros/assert-ne-macro-success.rs
@@ -0,0 +1,13 @@
+// run-pass
+#[derive(PartialEq, Debug)]
+struct Point { x : isize }
+
+pub fn main() {
+    assert_ne!(666,14);
+    assert_ne!("666".to_string(),"abc".to_string());
+    assert_ne!(Box::new(Point{x:666}),Box::new(Point{x:34}));
+    assert_ne!(&Point{x:666},&Point{x:34});
+    assert_ne!(666, 42, "no gods no masters");
+    assert_ne!(666, 42, "6 {} 6", "6");
+    assert_ne!(666, 42, "{x}, {y}, {z}", x = 6, y = 6, z = 6);
+}
diff --git a/tests/ui/macros/assert-ne-macro-unsized.rs b/tests/ui/macros/assert-ne-macro-unsized.rs
new file mode 100644
index 00000000000..e8a86e3da06
--- /dev/null
+++ b/tests/ui/macros/assert-ne-macro-unsized.rs
@@ -0,0 +1,4 @@
+// run-pass
+pub fn main() {
+    assert_ne!([6, 6, 6][..], vec![1, 2, 3][..]);
+}
diff --git a/tests/ui/macros/assert-trailing-junk.rs b/tests/ui/macros/assert-trailing-junk.rs
new file mode 100644
index 00000000000..da725e19e2a
--- /dev/null
+++ b/tests/ui/macros/assert-trailing-junk.rs
@@ -0,0 +1,27 @@
+// revisions: with-generic-asset without-generic-asset
+// [with-generic-asset] compile-flags: --cfg feature="generic_assert"
+
+// Ensure assert macro does not ignore trailing garbage.
+//
+// See https://github.com/rust-lang/rust/issues/60024 for details.
+
+fn main() {
+    assert!(true some extra junk, "whatever");
+    //~^ ERROR expected one of
+
+    assert!(true some extra junk);
+    //~^ ERROR expected one of
+
+    assert!(true, "whatever" blah);
+    //~^ ERROR no rules expected
+
+    assert!(true "whatever" blah);
+    //~^ ERROR unexpected string literal
+    //~^^ ERROR no rules expected
+
+    assert!(true;);
+    //~^ ERROR macro requires an expression
+
+    assert!(false || true "error message");
+    //~^ ERROR unexpected string literal
+}
diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
new file mode 100644
index 00000000000..1e73320e439
--- /dev/null
+++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
@@ -0,0 +1,58 @@
+error: expected one of `,`, `.`, `?`, or an operator, found `some`
+  --> $DIR/assert-trailing-junk.rs:9:18
+   |
+LL |     assert!(true some extra junk, "whatever");
+   |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `,`, `.`, `?`, or an operator, found `some`
+  --> $DIR/assert-trailing-junk.rs:12:18
+   |
+LL |     assert!(true some extra junk);
+   |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: no rules expected the token `blah`
+  --> $DIR/assert-trailing-junk.rs:15:30
+   |
+LL |     assert!(true, "whatever" blah);
+   |                             -^^^^ no rules expected this token in macro call
+   |                             |
+   |                             help: missing comma here
+   |
+   = note: while trying to match sequence start
+
+error: unexpected string literal
+  --> $DIR/assert-trailing-junk.rs:18:18
+   |
+LL |     assert!(true "whatever" blah);
+   |                 -^^^^^^^^^^
+   |                 |
+   |                 help: try adding a comma
+
+error: no rules expected the token `blah`
+  --> $DIR/assert-trailing-junk.rs:18:29
+   |
+LL |     assert!(true "whatever" blah);
+   |                            -^^^^ no rules expected this token in macro call
+   |                            |
+   |                            help: missing comma here
+   |
+   = note: while trying to match sequence start
+
+error: macro requires an expression as an argument
+  --> $DIR/assert-trailing-junk.rs:22:5
+   |
+LL |     assert!(true;);
+   |     ^^^^^^^^^^^^-^
+   |                 |
+   |                 help: try removing semicolon
+
+error: unexpected string literal
+  --> $DIR/assert-trailing-junk.rs:25:27
+   |
+LL |     assert!(false || true "error message");
+   |                          -^^^^^^^^^^^^^^^
+   |                          |
+   |                          help: try adding a comma
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
new file mode 100644
index 00000000000..1e73320e439
--- /dev/null
+++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
@@ -0,0 +1,58 @@
+error: expected one of `,`, `.`, `?`, or an operator, found `some`
+  --> $DIR/assert-trailing-junk.rs:9:18
+   |
+LL |     assert!(true some extra junk, "whatever");
+   |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `,`, `.`, `?`, or an operator, found `some`
+  --> $DIR/assert-trailing-junk.rs:12:18
+   |
+LL |     assert!(true some extra junk);
+   |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: no rules expected the token `blah`
+  --> $DIR/assert-trailing-junk.rs:15:30
+   |
+LL |     assert!(true, "whatever" blah);
+   |                             -^^^^ no rules expected this token in macro call
+   |                             |
+   |                             help: missing comma here
+   |
+   = note: while trying to match sequence start
+
+error: unexpected string literal
+  --> $DIR/assert-trailing-junk.rs:18:18
+   |
+LL |     assert!(true "whatever" blah);
+   |                 -^^^^^^^^^^
+   |                 |
+   |                 help: try adding a comma
+
+error: no rules expected the token `blah`
+  --> $DIR/assert-trailing-junk.rs:18:29
+   |
+LL |     assert!(true "whatever" blah);
+   |                            -^^^^ no rules expected this token in macro call
+   |                            |
+   |                            help: missing comma here
+   |
+   = note: while trying to match sequence start
+
+error: macro requires an expression as an argument
+  --> $DIR/assert-trailing-junk.rs:22:5
+   |
+LL |     assert!(true;);
+   |     ^^^^^^^^^^^^-^
+   |                 |
+   |                 help: try removing semicolon
+
+error: unexpected string literal
+  --> $DIR/assert-trailing-junk.rs:25:27
+   |
+LL |     assert!(false || true "error message");
+   |                          -^^^^^^^^^^^^^^^
+   |                          |
+   |                          help: try adding a comma
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/macros/assert.rs b/tests/ui/macros/assert.rs
new file mode 100644
index 00000000000..a314db907b8
--- /dev/null
+++ b/tests/ui/macros/assert.rs
@@ -0,0 +1,9 @@
+// revisions: with-generic-asset without-generic-asset
+// [with-generic-asset] compile-flags: --cfg feature="generic_assert"
+
+fn main() {
+    assert!();  //~ ERROR requires a boolean expression
+    assert!(struct); //~ ERROR expected expression
+    debug_assert!(); //~ ERROR requires a boolean expression
+    debug_assert!(struct); //~ ERROR expected expression
+}
diff --git a/tests/ui/macros/assert.with-generic-asset.stderr b/tests/ui/macros/assert.with-generic-asset.stderr
new file mode 100644
index 00000000000..51d8f28a35c
--- /dev/null
+++ b/tests/ui/macros/assert.with-generic-asset.stderr
@@ -0,0 +1,28 @@
+error: macro requires a boolean expression as an argument
+  --> $DIR/assert.rs:5:5
+   |
+LL |     assert!();
+   |     ^^^^^^^^^ boolean expression required
+
+error: expected expression, found keyword `struct`
+  --> $DIR/assert.rs:6:13
+   |
+LL |     assert!(struct);
+   |             ^^^^^^ expected expression
+
+error: macro requires a boolean expression as an argument
+  --> $DIR/assert.rs:7:5
+   |
+LL |     debug_assert!();
+   |     ^^^^^^^^^^^^^^^ boolean expression required
+   |
+   = note: this error originates in the macro `debug_assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found keyword `struct`
+  --> $DIR/assert.rs:8:19
+   |
+LL |     debug_assert!(struct);
+   |                   ^^^^^^ expected expression
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/assert.without-generic-asset.stderr b/tests/ui/macros/assert.without-generic-asset.stderr
new file mode 100644
index 00000000000..51d8f28a35c
--- /dev/null
+++ b/tests/ui/macros/assert.without-generic-asset.stderr
@@ -0,0 +1,28 @@
+error: macro requires a boolean expression as an argument
+  --> $DIR/assert.rs:5:5
+   |
+LL |     assert!();
+   |     ^^^^^^^^^ boolean expression required
+
+error: expected expression, found keyword `struct`
+  --> $DIR/assert.rs:6:13
+   |
+LL |     assert!(struct);
+   |             ^^^^^^ expected expression
+
+error: macro requires a boolean expression as an argument
+  --> $DIR/assert.rs:7:5
+   |
+LL |     debug_assert!();
+   |     ^^^^^^^^^^^^^^^ boolean expression required
+   |
+   = note: this error originates in the macro `debug_assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found keyword `struct`
+  --> $DIR/assert.rs:8:19
+   |
+LL |     debug_assert!(struct);
+   |                   ^^^^^^ expected expression
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/attr-empty-expr.rs b/tests/ui/macros/attr-empty-expr.rs
new file mode 100644
index 00000000000..d4d1a3ee71e
--- /dev/null
+++ b/tests/ui/macros/attr-empty-expr.rs
@@ -0,0 +1,11 @@
+// AST-based macro attributes expanding to an empty expression produce an error and not ICE.
+
+#![feature(custom_test_frameworks)]
+#![feature(stmt_expr_attributes)]
+#![feature(test)]
+
+fn main() {
+    let _ = #[test] 0; //~ ERROR removing an expression is not supported in this position
+    let _ = #[bench] 1; //~ ERROR removing an expression is not supported in this position
+    let _ = #[test_case] 2; //~ ERROR removing an expression is not supported in this position
+}
diff --git a/tests/ui/macros/attr-empty-expr.stderr b/tests/ui/macros/attr-empty-expr.stderr
new file mode 100644
index 00000000000..53721053bcc
--- /dev/null
+++ b/tests/ui/macros/attr-empty-expr.stderr
@@ -0,0 +1,20 @@
+error: removing an expression is not supported in this position
+  --> $DIR/attr-empty-expr.rs:8:13
+   |
+LL |     let _ = #[test] 0;
+   |             ^^^^^^^
+
+error: removing an expression is not supported in this position
+  --> $DIR/attr-empty-expr.rs:9:13
+   |
+LL |     let _ = #[bench] 1;
+   |             ^^^^^^^^
+
+error: removing an expression is not supported in this position
+  --> $DIR/attr-empty-expr.rs:10:13
+   |
+LL |     let _ = #[test_case] 2;
+   |             ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/attr-from-macro.rs b/tests/ui/macros/attr-from-macro.rs
new file mode 100644
index 00000000000..bb3a5c94d41
--- /dev/null
+++ b/tests/ui/macros/attr-from-macro.rs
@@ -0,0 +1,20 @@
+// aux-build:attr-from-macro.rs
+// run-pass
+
+extern crate attr_from_macro;
+
+attr_from_macro::creator! {
+    struct Foo;
+    enum Bar;
+    enum FooBar;
+}
+
+fn main() {
+    // Checking the `repr(u32)` on the enum.
+    assert_eq!(4, std::mem::size_of::<Bar>());
+    // Checking the `repr(u16)` on the enum.
+    assert_eq!(2, std::mem::size_of::<FooBar>());
+
+    // Checking the Debug impl on the types.
+    eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A);
+}
diff --git a/tests/ui/macros/auxiliary/attr-from-macro.rs b/tests/ui/macros/auxiliary/attr-from-macro.rs
new file mode 100644
index 00000000000..9b388675c80
--- /dev/null
+++ b/tests/ui/macros/auxiliary/attr-from-macro.rs
@@ -0,0 +1,15 @@
+#[macro_export]
+macro_rules! creator {
+    (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => {
+        #[derive(Debug)]
+        pub struct $name1;
+
+        #[derive(Debug)]
+        #[repr(u32)]
+        pub enum $name2 { A }
+
+        #[derive(Debug)]
+        #[repr(u16)]
+        pub enum $name3 { A }
+    }
+}
diff --git a/tests/ui/macros/auxiliary/define-macro.rs b/tests/ui/macros/auxiliary/define-macro.rs
new file mode 100644
index 00000000000..4956907c55e
--- /dev/null
+++ b/tests/ui/macros/auxiliary/define-macro.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! define_macro {
+    ($i:ident) => {
+        macro_rules! $i { () => {} }
+    }
+}
diff --git a/tests/ui/macros/auxiliary/deprecated-macros.rs b/tests/ui/macros/auxiliary/deprecated-macros.rs
new file mode 100644
index 00000000000..657a7252a36
--- /dev/null
+++ b/tests/ui/macros/auxiliary/deprecated-macros.rs
@@ -0,0 +1,3 @@
+#[deprecated(since = "1.0.0", note = "deprecation note")]
+#[macro_export]
+macro_rules! deprecated_macro{ () => () }
diff --git a/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs b/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs
new file mode 100644
index 00000000000..bbe6a48c5b1
--- /dev/null
+++ b/tests/ui/macros/auxiliary/dollar-crate-nested-encoding.rs
@@ -0,0 +1,10 @@
+pub type S = u8;
+
+macro_rules! generate_exported { () => {
+    #[macro_export]
+    macro_rules! exported {
+        () => ($crate::S)
+    }
+}}
+
+generate_exported!();
diff --git a/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs
new file mode 100644
index 00000000000..26d4c96d524
--- /dev/null
+++ b/tests/ui/macros/auxiliary/foreign-crate-macro-pat.rs
@@ -0,0 +1,11 @@
+// edition:2018
+
+#[macro_export]
+macro_rules! custom_matches {
+    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+        match $expression {
+            $( $pattern )|+ $( if $guard )? => true,
+            _ => false
+        }
+    }
+}
diff --git a/tests/ui/macros/auxiliary/issue-100199.rs b/tests/ui/macros/auxiliary/issue-100199.rs
new file mode 100644
index 00000000000..9e190b542db
--- /dev/null
+++ b/tests/ui/macros/auxiliary/issue-100199.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, Ident, Span, TokenStream, TokenTree};
+
+#[proc_macro_attribute]
+pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream {
+    let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site()));
+    let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site()));
+    quote!(
+        struct Foo<T: $crate_ident::$trait_ident> {}
+    )
+}
diff --git a/tests/ui/macros/auxiliary/issue-19163.rs b/tests/ui/macros/auxiliary/issue-19163.rs
new file mode 100644
index 00000000000..0c0d9e43c1d
--- /dev/null
+++ b/tests/ui/macros/auxiliary/issue-19163.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+
+#[macro_export]
+macro_rules! mywrite {
+    ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
+}
diff --git a/tests/ui/macros/auxiliary/issue-40469.rs b/tests/ui/macros/auxiliary/issue-40469.rs
new file mode 100644
index 00000000000..4f2f41f2cde
--- /dev/null
+++ b/tests/ui/macros/auxiliary/issue-40469.rs
@@ -0,0 +1 @@
+macro_rules! m { () => { $crate::main(); } }
diff --git a/tests/ui/macros/auxiliary/issue-75982.rs b/tests/ui/macros/auxiliary/issue-75982.rs
new file mode 100644
index 00000000000..1e1a6126a10
--- /dev/null
+++ b/tests/ui/macros/auxiliary/issue-75982.rs
@@ -0,0 +1,12 @@
+const _: () = {
+    #[macro_export]
+    macro_rules! first_macro {
+        () => {}
+    }
+    mod foo {
+        #[macro_export]
+        macro_rules! second_macro {
+            () => {}
+        }
+    }
+};
diff --git a/tests/ui/macros/auxiliary/macro-comma-support.rs b/tests/ui/macros/auxiliary/macro-comma-support.rs
new file mode 100644
index 00000000000..6a452c185a8
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro-comma-support.rs
@@ -0,0 +1 @@
+()
diff --git a/tests/ui/macros/auxiliary/macro-def-site-super.rs b/tests/ui/macros/auxiliary/macro-def-site-super.rs
new file mode 100644
index 00000000000..cab747c2c05
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro-def-site-super.rs
@@ -0,0 +1,13 @@
+#![feature(decl_macro)]
+
+mod inner1 {
+    pub struct Struct {}
+
+    pub mod inner2 {
+        pub macro mac() {
+            super::Struct
+        }
+    }
+}
+
+pub use inner1::inner2 as public;
diff --git a/tests/ui/macros/auxiliary/macro-in-other-crate.rs b/tests/ui/macros/auxiliary/macro-in-other-crate.rs
new file mode 100644
index 00000000000..db8e9201865
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro-in-other-crate.rs
@@ -0,0 +1,14 @@
+#[macro_export]
+macro_rules! mac {
+    ($ident:ident) => { let $ident = 42; }
+}
+
+#[macro_export]
+macro_rules! inline {
+    () => ()
+}
+
+#[macro_export]
+macro_rules! from_prelude {
+    () => ()
+}
diff --git a/tests/ui/macros/auxiliary/macro-include-items-expr.rs b/tests/ui/macros/auxiliary/macro-include-items-expr.rs
new file mode 100644
index 00000000000..7394f194b80
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro-include-items-expr.rs
@@ -0,0 +1,3 @@
+// ignore-test: this is not a test
+
+1
diff --git a/tests/ui/macros/auxiliary/macro-include-items-item.rs b/tests/ui/macros/auxiliary/macro-include-items-item.rs
new file mode 100644
index 00000000000..7d54745e03b
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro-include-items-item.rs
@@ -0,0 +1,3 @@
+// ignore-test: this is not a test
+
+fn foo() { bar() }
diff --git a/tests/ui/macros/auxiliary/macro_crate_def_only.rs b/tests/ui/macros/auxiliary/macro_crate_def_only.rs
new file mode 100644
index 00000000000..c267eefde02
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro_crate_def_only.rs
@@ -0,0 +1,4 @@
+#[macro_export]
+macro_rules! make_a_5 {
+    () => (5)
+}
diff --git a/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs b/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs
new file mode 100644
index 00000000000..2e2440462ae
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro_crate_nonterminal.rs
@@ -0,0 +1,12 @@
+pub fn increment(x: usize) -> usize {
+    x + 1
+}
+
+#[macro_export]
+macro_rules! increment {
+    ($x:expr) => ($crate::increment($x))
+}
+
+pub fn check_local() {
+    assert_eq!(increment!(3), 4);
+}
diff --git a/tests/ui/macros/auxiliary/macro_export_inner_module.rs b/tests/ui/macros/auxiliary/macro_export_inner_module.rs
new file mode 100644
index 00000000000..d71af9ee6f2
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro_export_inner_module.rs
@@ -0,0 +1,6 @@
+pub mod inner {
+    #[macro_export]
+    macro_rules! foo {
+        () => (1)
+    }
+}
diff --git a/tests/ui/macros/auxiliary/macro_with_super_1.rs b/tests/ui/macros/auxiliary/macro_with_super_1.rs
new file mode 100644
index 00000000000..b015500df06
--- /dev/null
+++ b/tests/ui/macros/auxiliary/macro_with_super_1.rs
@@ -0,0 +1,16 @@
+#![crate_type = "lib"]
+
+#[macro_export]
+macro_rules! declare {
+    () => (
+        pub fn aaa() {}
+
+        pub mod bbb {
+            use super::aaa;
+
+            pub fn ccc() {
+                aaa();
+            }
+        }
+    )
+}
diff --git a/tests/ui/macros/auxiliary/or-pattern.rs b/tests/ui/macros/auxiliary/or-pattern.rs
new file mode 100644
index 00000000000..a319c405eb6
--- /dev/null
+++ b/tests/ui/macros/auxiliary/or-pattern.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+
+#[macro_export]
+macro_rules! a {
+    ($x:pat|) => ();
+}
diff --git a/tests/ui/macros/auxiliary/proc_macro_def.rs b/tests/ui/macros/auxiliary/proc_macro_def.rs
new file mode 100644
index 00000000000..0497e4ae07d
--- /dev/null
+++ b/tests/ui/macros/auxiliary/proc_macro_def.rs
@@ -0,0 +1,35 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_attribute]
+pub fn attr_tru(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    let name = item.into_iter().nth(1).unwrap();
+    quote!(fn $name() -> bool { true })
+}
+
+#[proc_macro_attribute]
+pub fn attr_identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    quote!($item)
+}
+
+#[proc_macro]
+pub fn tru(_ts: TokenStream) -> TokenStream {
+    quote!(true)
+}
+
+#[proc_macro]
+pub fn ret_tru(_ts: TokenStream) -> TokenStream {
+    quote!(return true;)
+}
+
+#[proc_macro]
+pub fn identity(ts: TokenStream) -> TokenStream {
+    quote!($ts)
+}
diff --git a/tests/ui/macros/auxiliary/proc_macro_sequence.rs b/tests/ui/macros/auxiliary/proc_macro_sequence.rs
new file mode 100644
index 00000000000..1331480d835
--- /dev/null
+++ b/tests/ui/macros/auxiliary/proc_macro_sequence.rs
@@ -0,0 +1,27 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_span, proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, Span, TokenStream, TokenTree};
+
+fn assert_same_span(a: Span, b: Span) {
+    assert_eq!(a.start(), b.start());
+    assert_eq!(a.end(), b.end());
+}
+
+// This macro generates a macro with the same macro definition as `manual_foo` in
+// `same-sequence-span.rs` but with the same span for all sequences.
+#[proc_macro]
+pub fn make_foo(_: TokenStream) -> TokenStream {
+    let result = quote! {
+        macro_rules! generated_foo {
+            (1 $$x:expr $$($$y:tt,)* $$(= $$z:tt)*) => {};
+        }
+    };
+
+    result
+}
diff --git a/tests/ui/macros/auxiliary/two_macros-rpass.rs b/tests/ui/macros/auxiliary/two_macros-rpass.rs
new file mode 100644
index 00000000000..441a978dd69
--- /dev/null
+++ b/tests/ui/macros/auxiliary/two_macros-rpass.rs
@@ -0,0 +1,5 @@
+#[macro_export]
+macro_rules! macro_one { ($($t:tt)*) => ($($t)*) }
+
+#[macro_export]
+macro_rules! macro_two { ($($t:tt)*) => ($($t)*) }
diff --git a/tests/ui/macros/auxiliary/two_macros.rs b/tests/ui/macros/auxiliary/two_macros.rs
new file mode 100644
index 00000000000..2330c75c8e0
--- /dev/null
+++ b/tests/ui/macros/auxiliary/two_macros.rs
@@ -0,0 +1,5 @@
+#[macro_export]
+macro_rules! macro_one { () => ("one") }
+
+#[macro_export]
+macro_rules! macro_two { () => ("two") }
diff --git a/tests/ui/macros/auxiliary/unstable-macros.rs b/tests/ui/macros/auxiliary/unstable-macros.rs
new file mode 100644
index 00000000000..3aadd4b0ca6
--- /dev/null
+++ b/tests/ui/macros/auxiliary/unstable-macros.rs
@@ -0,0 +1,16 @@
+#![feature(decl_macro)]
+#![feature(staged_api)]
+#![stable(feature = "unit_test", since = "1.0.0")]
+
+#[unstable(feature = "unstable_macros", issue = "none")]
+#[macro_export]
+macro_rules! unstable_macro{ () => () }
+
+#[stable(feature = "deprecated_macros", since = "1.0.0")]
+#[deprecated(since = "1.0.0", note = "deprecation note")]
+#[macro_export]
+macro_rules! deprecated_macro{ () => () }
+
+// FIXME: Cannot use a `pub` macro 2.0 in a staged API crate due to reachability issues.
+// #[unstable(feature = "unstable_macros", issue = "none")]
+// pub macro unstable_macro_modern() {}
diff --git a/tests/ui/macros/auxiliary/use-macro-self.rs b/tests/ui/macros/auxiliary/use-macro-self.rs
new file mode 100644
index 00000000000..f1307411a7f
--- /dev/null
+++ b/tests/ui/macros/auxiliary/use-macro-self.rs
@@ -0,0 +1,6 @@
+pub mod foobarius {}
+
+#[macro_export]
+macro_rules! foobarius {
+    () => { () }
+}
diff --git a/tests/ui/macros/bad-concat.rs b/tests/ui/macros/bad-concat.rs
new file mode 100644
index 00000000000..263cd074d5a
--- /dev/null
+++ b/tests/ui/macros/bad-concat.rs
@@ -0,0 +1,8 @@
+fn main() {
+    let x: u32 = 42;
+    let y: f64 = 3.14;
+    let z = "foo";
+    let _ = concat!(x, y, z, "bar");
+    //~^ ERROR expected a literal
+    //~| NOTE only literals
+}
diff --git a/tests/ui/macros/bad-concat.stderr b/tests/ui/macros/bad-concat.stderr
new file mode 100644
index 00000000000..4316fd312c7
--- /dev/null
+++ b/tests/ui/macros/bad-concat.stderr
@@ -0,0 +1,10 @@
+error: expected a literal
+  --> $DIR/bad-concat.rs:5:21
+   |
+LL |     let _ = concat!(x, y, z, "bar");
+   |                     ^  ^  ^
+   |
+   = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/bad_hello.rs b/tests/ui/macros/bad_hello.rs
new file mode 100644
index 00000000000..aaa9e243a2d
--- /dev/null
+++ b/tests/ui/macros/bad_hello.rs
@@ -0,0 +1,6 @@
+fn main() {
+    println!(3 + 4);
+    //~^ ERROR format argument must be a string literal
+    println!(3, 4);
+    //~^ ERROR format argument must be a string literal
+}
diff --git a/tests/ui/macros/bad_hello.stderr b/tests/ui/macros/bad_hello.stderr
new file mode 100644
index 00000000000..fc9bb82b784
--- /dev/null
+++ b/tests/ui/macros/bad_hello.stderr
@@ -0,0 +1,24 @@
+error: format argument must be a string literal
+  --> $DIR/bad_hello.rs:2:14
+   |
+LL |     println!(3 + 4);
+   |              ^^^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{}", 3 + 4);
+   |              +++++
+
+error: format argument must be a string literal
+  --> $DIR/bad_hello.rs:4:14
+   |
+LL |     println!(3, 4);
+   |              ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{} {}", 3, 4);
+   |              ++++++++
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/bang-after-name.fixed b/tests/ui/macros/bang-after-name.fixed
new file mode 100644
index 00000000000..c107ddd5d03
--- /dev/null
+++ b/tests/ui/macros/bang-after-name.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo { //~ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/tests/ui/macros/bang-after-name.rs b/tests/ui/macros/bang-after-name.rs
new file mode 100644
index 00000000000..7654d8c4403
--- /dev/null
+++ b/tests/ui/macros/bang-after-name.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo! { //~ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/tests/ui/macros/bang-after-name.stderr b/tests/ui/macros/bang-after-name.stderr
new file mode 100644
index 00000000000..f609c4943ef
--- /dev/null
+++ b/tests/ui/macros/bang-after-name.stderr
@@ -0,0 +1,8 @@
+error: macro names aren't followed by a `!`
+  --> $DIR/bang-after-name.rs:4:17
+   |
+LL | macro_rules! foo! {
+   |                 ^ help: remove the `!`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs
new file mode 100644
index 00000000000..bbdd465d5ec
--- /dev/null
+++ b/tests/ui/macros/best-failure.rs
@@ -0,0 +1,11 @@
+macro_rules! number {
+    (neg false, $self:ident) => { $self };
+    ($signed:tt => $ty:ty;) => {
+        number!(neg $signed, $self);
+        //~^ ERROR no rules expected the token `$`
+    };
+}
+
+number! { false => u8; }
+
+fn main() {}
diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr
new file mode 100644
index 00000000000..a52fc5e3da6
--- /dev/null
+++ b/tests/ui/macros/best-failure.stderr
@@ -0,0 +1,21 @@
+error: no rules expected the token `$`
+  --> $DIR/best-failure.rs:4:30
+   |
+LL | macro_rules! number {
+   | ------------------- when calling this macro
+...
+LL |         number!(neg $signed, $self);
+   |                              ^^^^^ no rules expected this token in macro call
+...
+LL | number! { false => u8; }
+   | ------------------------ in this macro invocation
+   |
+note: while trying to match meta-variable `$self:ident`
+  --> $DIR/best-failure.rs:2:17
+   |
+LL |     (neg false, $self:ident) => { $self };
+   |                 ^^^^^^^^^^^
+   = note: this error originates in the macro `number` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/builtin-prelude-no-accidents.rs b/tests/ui/macros/builtin-prelude-no-accidents.rs
new file mode 100644
index 00000000000..01691a82dd7
--- /dev/null
+++ b/tests/ui/macros/builtin-prelude-no-accidents.rs
@@ -0,0 +1,8 @@
+// Names of public modules in libstd and libcore don't accidentally get into prelude
+// because macros with the same names are in prelude.
+
+fn main() {
+    env::current_dir; //~ ERROR use of undeclared crate or module `env`
+    type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic`
+    type B = vec::Vec<u8>; //~ ERROR use of undeclared crate or module `vec`
+}
diff --git a/tests/ui/macros/builtin-prelude-no-accidents.stderr b/tests/ui/macros/builtin-prelude-no-accidents.stderr
new file mode 100644
index 00000000000..56af618d484
--- /dev/null
+++ b/tests/ui/macros/builtin-prelude-no-accidents.stderr
@@ -0,0 +1,21 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `env`
+  --> $DIR/builtin-prelude-no-accidents.rs:5:5
+   |
+LL |     env::current_dir;
+   |     ^^^ use of undeclared crate or module `env`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `panic`
+  --> $DIR/builtin-prelude-no-accidents.rs:6:14
+   |
+LL |     type A = panic::PanicInfo;
+   |              ^^^^^ use of undeclared crate or module `panic`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `vec`
+  --> $DIR/builtin-prelude-no-accidents.rs:7:14
+   |
+LL |     type B = vec::Vec<u8>;
+   |              ^^^ use of undeclared crate or module `vec`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/builtin-std-paths-fail.rs b/tests/ui/macros/builtin-std-paths-fail.rs
new file mode 100644
index 00000000000..c1a4e32a6dc
--- /dev/null
+++ b/tests/ui/macros/builtin-std-paths-fail.rs
@@ -0,0 +1,25 @@
+#[derive(
+    core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core`
+                          //~| ERROR could not find `RustcDecodable` in `core`
+    core::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `core`
+                          //~| ERROR could not find `RustcDecodable` in `core`
+)]
+#[core::bench] //~ ERROR could not find `bench` in `core`
+#[core::global_allocator] //~ ERROR could not find `global_allocator` in `core`
+#[core::test_case] //~ ERROR could not find `test_case` in `core`
+#[core::test] //~ ERROR could not find `test` in `core`
+struct Core;
+
+#[derive(
+    std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std`
+                         //~| ERROR could not find `RustcDecodable` in `std`
+    std::RustcDecodable, //~ ERROR could not find `RustcDecodable` in `std`
+                         //~| ERROR could not find `RustcDecodable` in `std`
+)]
+#[std::bench] //~ ERROR could not find `bench` in `std`
+#[std::global_allocator] //~ ERROR could not find `global_allocator` in `std`
+#[std::test_case] //~ ERROR could not find `test_case` in `std`
+#[std::test] //~ ERROR could not find `test` in `std`
+struct Std;
+
+fn main() {}
diff --git a/tests/ui/macros/builtin-std-paths-fail.stderr b/tests/ui/macros/builtin-std-paths-fail.stderr
new file mode 100644
index 00000000000..ba626101190
--- /dev/null
+++ b/tests/ui/macros/builtin-std-paths-fail.stderr
@@ -0,0 +1,99 @@
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:2:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:2:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:4:11
+   |
+LL |     core::RustcDecodable,
+   |           ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `core`
+
+error[E0433]: failed to resolve: could not find `bench` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:7:9
+   |
+LL | #[core::bench]
+   |         ^^^^^ could not find `bench` in `core`
+
+error[E0433]: failed to resolve: could not find `global_allocator` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:8:9
+   |
+LL | #[core::global_allocator]
+   |         ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `core`
+
+error[E0433]: failed to resolve: could not find `test_case` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:9:9
+   |
+LL | #[core::test_case]
+   |         ^^^^^^^^^ could not find `test_case` in `core`
+
+error[E0433]: failed to resolve: could not find `test` in `core`
+  --> $DIR/builtin-std-paths-fail.rs:10:9
+   |
+LL | #[core::test]
+   |         ^^^^ could not find `test` in `core`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:14:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:14:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `RustcDecodable` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:16:10
+   |
+LL |     std::RustcDecodable,
+   |          ^^^^^^^^^^^^^^ could not find `RustcDecodable` in `std`
+
+error[E0433]: failed to resolve: could not find `bench` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:19:8
+   |
+LL | #[std::bench]
+   |        ^^^^^ could not find `bench` in `std`
+
+error[E0433]: failed to resolve: could not find `global_allocator` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:20:8
+   |
+LL | #[std::global_allocator]
+   |        ^^^^^^^^^^^^^^^^ could not find `global_allocator` in `std`
+
+error[E0433]: failed to resolve: could not find `test_case` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:21:8
+   |
+LL | #[std::test_case]
+   |        ^^^^^^^^^ could not find `test_case` in `std`
+
+error[E0433]: failed to resolve: could not find `test` in `std`
+  --> $DIR/builtin-std-paths-fail.rs:22:8
+   |
+LL | #[std::test]
+   |        ^^^^ could not find `test` in `std`
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/builtin-std-paths.rs b/tests/ui/macros/builtin-std-paths.rs
new file mode 100644
index 00000000000..2083f9ba3dc
--- /dev/null
+++ b/tests/ui/macros/builtin-std-paths.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#[derive(
+    core::clone::Clone,
+    core::marker::Copy,
+    core::fmt::Debug,
+    core::default::Default,
+    core::cmp::Eq,
+    core::hash::Hash,
+    core::cmp::Ord,
+    core::cmp::PartialEq,
+    core::cmp::PartialOrd,
+)]
+struct Core;
+
+#[derive(
+    std::clone::Clone,
+    std::marker::Copy,
+    std::fmt::Debug,
+    std::default::Default,
+    std::cmp::Eq,
+    std::hash::Hash,
+    std::cmp::Ord,
+    std::cmp::PartialEq,
+    std::cmp::PartialOrd,
+)]
+struct Std;
+
+fn main() {
+    core::column!();
+    std::column!();
+}
diff --git a/tests/ui/macros/cfg.rs b/tests/ui/macros/cfg.rs
new file mode 100644
index 00000000000..2aac50a9d01
--- /dev/null
+++ b/tests/ui/macros/cfg.rs
@@ -0,0 +1,6 @@
+fn main() {
+    cfg!(); //~ ERROR macro requires a cfg-pattern
+    cfg!(123); //~ ERROR expected identifier
+    cfg!(foo = 123); //~ ERROR literal in `cfg` predicate value must be a string
+    cfg!(foo, bar); //~ ERROR expected 1 cfg-pattern
+}
diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr
new file mode 100644
index 00000000000..2633d5f720d
--- /dev/null
+++ b/tests/ui/macros/cfg.stderr
@@ -0,0 +1,31 @@
+error: macro requires a cfg-pattern as an argument
+  --> $DIR/cfg.rs:2:5
+   |
+LL |     cfg!();
+   |     ^^^^^^ cfg-pattern required
+   |
+   = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected identifier, found `123`
+  --> $DIR/cfg.rs:3:10
+   |
+LL |     cfg!(123);
+   |          ^^^ expected identifier
+
+error[E0565]: literal in `cfg` predicate value must be a string
+  --> $DIR/cfg.rs:4:16
+   |
+LL |     cfg!(foo = 123);
+   |                ^^^
+
+error: expected 1 cfg-pattern
+  --> $DIR/cfg.rs:5:5
+   |
+LL |     cfg!(foo, bar);
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `cfg` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0565`.
diff --git a/tests/ui/macros/colorful-write-macros.rs b/tests/ui/macros/colorful-write-macros.rs
new file mode 100644
index 00000000000..eb1872cc7f0
--- /dev/null
+++ b/tests/ui/macros/colorful-write-macros.rs
@@ -0,0 +1,34 @@
+// run-pass
+#![allow(dead_code)]
+use std::io::Write;
+use std::fmt;
+
+struct Foo<'a> {
+    writer: &'a mut (dyn Write+'a),
+    other: &'a str,
+}
+
+struct Bar;
+
+impl fmt::Write for Bar {
+    fn write_str(&mut self, _: &str) -> fmt::Result {
+        Ok(())
+    }
+}
+
+fn borrowing_writer_from_struct_and_formatting_struct_field(foo: Foo) {
+    write!(foo.writer, "{}", foo.other).unwrap();
+}
+
+fn main() {
+    let mut w = Vec::new();
+    write!(&mut w as &mut dyn Write, "").unwrap();
+    write!(&mut w, "").unwrap(); // should coerce
+    println!("ok");
+
+    let mut s = Bar;
+    {
+        use std::fmt::Write;
+        write!(&mut s, "test").unwrap();
+    }
+}
diff --git a/tests/ui/macros/concat-bytes-error.rs b/tests/ui/macros/concat-bytes-error.rs
new file mode 100644
index 00000000000..db5d3cab0bd
--- /dev/null
+++ b/tests/ui/macros/concat-bytes-error.rs
@@ -0,0 +1,50 @@
+#![feature(concat_bytes)]
+
+fn main() {
+    concat_bytes!(pie); //~ ERROR expected a byte literal
+    concat_bytes!(pie, pie); //~ ERROR expected a byte literal
+    concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals
+    concat_bytes!(2.8); //~ ERROR cannot concatenate float literals
+    concat_bytes!(300); //~ ERROR cannot concatenate numeric literals
+    concat_bytes!('a'); //~ ERROR cannot concatenate character literals
+    concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals
+    concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals
+    concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals
+    concat_bytes!([
+        "hi", //~ ERROR cannot concatenate string literals
+    ]);
+    concat_bytes!([
+        'a', //~ ERROR cannot concatenate character literals
+    ]);
+    concat_bytes!([
+        true, //~ ERROR cannot concatenate boolean literals
+    ]);
+    concat_bytes!([
+        false, //~ ERROR cannot concatenate boolean literals
+    ]);
+    concat_bytes!([
+        2.6, //~ ERROR cannot concatenate float literals
+    ]);
+    concat_bytes!([
+        265, //~ ERROR numeric literal is out of bounds
+    ]);
+    concat_bytes!([
+        -33, //~ ERROR expected a byte literal
+    ]);
+    concat_bytes!([
+        b"hi!", //~ ERROR cannot concatenate doubly nested array
+    ]);
+    concat_bytes!([
+        [5, 6, 7], //~ ERROR cannot concatenate doubly nested array
+    ]);
+    concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals
+    concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8`
+    concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([pie; -2]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([pie; 2]); //~ ERROR expected a byte literal
+    concat_bytes!([2.2; 0]); //~ ERROR cannot concatenate float literals
+    concat_bytes!([5.5; ()]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([[1, 2, 3]; 3]); //~ ERROR cannot concatenate doubly nested array
+    concat_bytes!([[42; 2]; 3]); //~ ERROR cannot concatenate doubly nested array
+}
diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr
new file mode 100644
index 00000000000..d6cd1a3d178
--- /dev/null
+++ b/tests/ui/macros/concat-bytes-error.stderr
@@ -0,0 +1,181 @@
+error: expected a byte literal
+  --> $DIR/concat-bytes-error.rs:4:19
+   |
+LL |     concat_bytes!(pie);
+   |                   ^^^
+   |
+   = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: expected a byte literal
+  --> $DIR/concat-bytes-error.rs:5:19
+   |
+LL |     concat_bytes!(pie, pie);
+   |                   ^^^  ^^^
+   |
+   = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate string literals
+  --> $DIR/concat-bytes-error.rs:6:19
+   |
+LL |     concat_bytes!("tnrsi", "tnri");
+   |                   ^^^^^^^ help: try using a byte string: `b"tnrsi"`
+
+error: cannot concatenate float literals
+  --> $DIR/concat-bytes-error.rs:7:19
+   |
+LL |     concat_bytes!(2.8);
+   |                   ^^^
+
+error: cannot concatenate numeric literals
+  --> $DIR/concat-bytes-error.rs:8:19
+   |
+LL |     concat_bytes!(300);
+   |                   ^^^ help: try wrapping the number in an array: `[300]`
+
+error: cannot concatenate character literals
+  --> $DIR/concat-bytes-error.rs:9:19
+   |
+LL |     concat_bytes!('a');
+   |                   ^^^ help: try using a byte character: `b'a'`
+
+error: cannot concatenate boolean literals
+  --> $DIR/concat-bytes-error.rs:10:19
+   |
+LL |     concat_bytes!(true, false);
+   |                   ^^^^
+
+error: cannot concatenate numeric literals
+  --> $DIR/concat-bytes-error.rs:11:19
+   |
+LL |     concat_bytes!(42, b"va", b'l');
+   |                   ^^ help: try wrapping the number in an array: `[42]`
+
+error: cannot concatenate numeric literals
+  --> $DIR/concat-bytes-error.rs:12:19
+   |
+LL |     concat_bytes!(42, b"va", b'l', [1, 2]);
+   |                   ^^ help: try wrapping the number in an array: `[42]`
+
+error: cannot concatenate string literals
+  --> $DIR/concat-bytes-error.rs:14:9
+   |
+LL |         "hi",
+   |         ^^^^
+
+error: cannot concatenate character literals
+  --> $DIR/concat-bytes-error.rs:17:9
+   |
+LL |         'a',
+   |         ^^^ help: try using a byte character: `b'a'`
+
+error: cannot concatenate boolean literals
+  --> $DIR/concat-bytes-error.rs:20:9
+   |
+LL |         true,
+   |         ^^^^
+
+error: cannot concatenate boolean literals
+  --> $DIR/concat-bytes-error.rs:23:9
+   |
+LL |         false,
+   |         ^^^^^
+
+error: cannot concatenate float literals
+  --> $DIR/concat-bytes-error.rs:26:9
+   |
+LL |         2.6,
+   |         ^^^
+
+error: numeric literal is out of bounds
+  --> $DIR/concat-bytes-error.rs:29:9
+   |
+LL |         265,
+   |         ^^^
+
+error: expected a byte literal
+  --> $DIR/concat-bytes-error.rs:32:9
+   |
+LL |         -33,
+   |         ^^^
+   |
+   = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:35:9
+   |
+LL |         b"hi!",
+   |         ^^^^^^
+   |
+   = note: byte strings are treated as arrays of bytes
+   = help: try flattening the array
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:38:9
+   |
+LL |         [5, 6, 7],
+   |         ^^^^^^^^^
+
+error: cannot concatenate numeric literals
+  --> $DIR/concat-bytes-error.rs:40:19
+   |
+LL |     concat_bytes!(5u16);
+   |                   ^^^^ help: try wrapping the number in an array: `[5u16]`
+
+error: numeric literal is not a `u8`
+  --> $DIR/concat-bytes-error.rs:41:20
+   |
+LL |     concat_bytes!([5u16]);
+   |                    ^^^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:42:23
+   |
+LL |     concat_bytes!([3; ()]);
+   |                       ^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:43:23
+   |
+LL |     concat_bytes!([3; -2]);
+   |                       ^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:44:25
+   |
+LL |     concat_bytes!([pie; -2]);
+   |                         ^^
+
+error: expected a byte literal
+  --> $DIR/concat-bytes-error.rs:45:20
+   |
+LL |     concat_bytes!([pie; 2]);
+   |                    ^^^
+   |
+   = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate float literals
+  --> $DIR/concat-bytes-error.rs:46:20
+   |
+LL |     concat_bytes!([2.2; 0]);
+   |                    ^^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:47:25
+   |
+LL |     concat_bytes!([5.5; ()]);
+   |                         ^^
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:48:20
+   |
+LL |     concat_bytes!([[1, 2, 3]; 3]);
+   |                    ^^^^^^^^^
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:49:20
+   |
+LL |     concat_bytes!([[42; 2]; 3]);
+   |                    ^^^^^^^
+
+error: aborting due to 28 previous errors
+
diff --git a/tests/ui/macros/concat-bytes.rs b/tests/ui/macros/concat-bytes.rs
new file mode 100644
index 00000000000..fd8f99417ec
--- /dev/null
+++ b/tests/ui/macros/concat-bytes.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(concat_bytes)]
+
+fn main() {
+    assert_eq!(concat_bytes!(), &[]);
+    assert_eq!(
+        concat_bytes!(b'A', b"BC", [68, b'E', 70], [b'G'; 1], [72; 2], [73u8; 3], [65; 0]),
+        b"ABCDEFGHHIII",
+    );
+    assert_eq!(
+        concat_bytes!(
+            concat_bytes!(b"AB", b"CD"),
+            concat_bytes!(b"EF", b"GH"),
+        ),
+        b"ABCDEFGH",
+    );
+}
diff --git a/tests/ui/macros/concat-rpass.rs b/tests/ui/macros/concat-rpass.rs
new file mode 100644
index 00000000000..0c30a39d6a2
--- /dev/null
+++ b/tests/ui/macros/concat-rpass.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+pub fn main() {
+    assert_eq!(format!(concat!("foo", "bar", "{}"), "baz"), "foobarbaz".to_string());
+    assert_eq!(format!(concat!()), "".to_string());
+    // check trailing comma is allowed in concat
+    assert_eq!(concat!("qux", "quux",).to_string(), "quxquux".to_string());
+
+    assert_eq!(
+        concat!(1, 2, 3, 4f32, 4.0, 'a', true),
+        "12344.0atrue"
+    );
+
+    assert!(match "12344.0atrue" {
+        concat!(1, 2, 3, 4f32, 4.0, 'a', true) => true,
+        _ => false
+    })
+}
diff --git a/tests/ui/macros/concat.rs b/tests/ui/macros/concat.rs
new file mode 100644
index 00000000000..d7ab7d62625
--- /dev/null
+++ b/tests/ui/macros/concat.rs
@@ -0,0 +1,6 @@
+fn main() {
+    concat!(b'f');  //~ ERROR: cannot concatenate a byte string literal
+    concat!(b"foo");  //~ ERROR: cannot concatenate a byte string literal
+    concat!(foo);   //~ ERROR: expected a literal
+    concat!(foo()); //~ ERROR: expected a literal
+}
diff --git a/tests/ui/macros/concat.stderr b/tests/ui/macros/concat.stderr
new file mode 100644
index 00000000000..61fb9de1ef9
--- /dev/null
+++ b/tests/ui/macros/concat.stderr
@@ -0,0 +1,30 @@
+error: cannot concatenate a byte string literal
+  --> $DIR/concat.rs:2:13
+   |
+LL |     concat!(b'f');
+   |             ^^^^
+
+error: cannot concatenate a byte string literal
+  --> $DIR/concat.rs:3:13
+   |
+LL |     concat!(b"foo");
+   |             ^^^^^^
+
+error: expected a literal
+  --> $DIR/concat.rs:4:13
+   |
+LL |     concat!(foo);
+   |             ^^^
+   |
+   = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()`
+
+error: expected a literal
+  --> $DIR/concat.rs:5:13
+   |
+LL |     concat!(foo());
+   |             ^^^^^
+   |
+   = note: only literals (like `"foo"`, `42` and `3.14`) can be passed to `concat!()`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/conditional-debug-macro-on.rs b/tests/ui/macros/conditional-debug-macro-on.rs
new file mode 100644
index 00000000000..8665da89758
--- /dev/null
+++ b/tests/ui/macros/conditional-debug-macro-on.rs
@@ -0,0 +1,8 @@
+// run-pass
+pub fn main() {
+    // exits early if println! evaluates its arguments, otherwise it
+    // will hit the panic.
+    println!("{:?}", { if true { return; } });
+
+    panic!();
+}
diff --git a/tests/ui/macros/cross-crate-pat-span.rs b/tests/ui/macros/cross-crate-pat-span.rs
new file mode 100644
index 00000000000..ed67142ce3d
--- /dev/null
+++ b/tests/ui/macros/cross-crate-pat-span.rs
@@ -0,0 +1,12 @@
+// edition:2021
+// check-pass
+// aux-build: foreign-crate-macro-pat.rs
+//
+// Tests that the edition of the foreign crate is used
+// when determining the behavior of the `:pat` matcher.
+
+extern crate foreign_crate_macro_pat;
+
+fn main() {
+    let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9');
+}
diff --git a/tests/ui/macros/derive-in-eager-expansion-hang.rs b/tests/ui/macros/derive-in-eager-expansion-hang.rs
new file mode 100644
index 00000000000..0729e14d5b2
--- /dev/null
+++ b/tests/ui/macros/derive-in-eager-expansion-hang.rs
@@ -0,0 +1,14 @@
+// Regression test for the issue #44692
+
+macro_rules! hang { () => {
+    { //~ ERROR format argument must be a string literal
+        #[derive(Clone)]
+        struct S;
+
+        ""
+    }
+}}
+
+fn main() {
+    format_args!(hang!());
+}
diff --git a/tests/ui/macros/derive-in-eager-expansion-hang.stderr b/tests/ui/macros/derive-in-eager-expansion-hang.stderr
new file mode 100644
index 00000000000..e0a4f3878d8
--- /dev/null
+++ b/tests/ui/macros/derive-in-eager-expansion-hang.stderr
@@ -0,0 +1,22 @@
+error: format argument must be a string literal
+  --> $DIR/derive-in-eager-expansion-hang.rs:4:5
+   |
+LL | /     {
+LL | |         #[derive(Clone)]
+LL | |         struct S;
+LL | |
+LL | |         ""
+LL | |     }
+   | |_____^
+...
+LL |       format_args!(hang!());
+   |                    ------- in this macro invocation
+   |
+   = note: this error originates in the macro `hang` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you might be missing a string literal to format with
+   |
+LL |     format_args!("{}", hang!());
+   |                  +++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/die-macro-2.rs b/tests/ui/macros/die-macro-2.rs
new file mode 100644
index 00000000000..ebbce528a18
--- /dev/null
+++ b/tests/ui/macros/die-macro-2.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:test
+// ignore-emscripten no processes
+
+fn main() {
+    panic!("test");
+}
diff --git a/tests/ui/macros/die-macro-expr.rs b/tests/ui/macros/die-macro-expr.rs
new file mode 100644
index 00000000000..c4b5f68ddf9
--- /dev/null
+++ b/tests/ui/macros/die-macro-expr.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:test
+// ignore-emscripten no processes
+
+fn main() {
+    let __isize: isize = panic!("test");
+}
diff --git a/tests/ui/macros/die-macro-pure.rs b/tests/ui/macros/die-macro-pure.rs
new file mode 100644
index 00000000000..588fbe61b0e
--- /dev/null
+++ b/tests/ui/macros/die-macro-pure.rs
@@ -0,0 +1,11 @@
+// run-fail
+// error-pattern:test
+// ignore-emscripten no processes
+
+fn f() {
+    panic!("test");
+}
+
+fn main() {
+    f();
+}
diff --git a/tests/ui/macros/die-macro.rs b/tests/ui/macros/die-macro.rs
new file mode 100644
index 00000000000..2a726efe822
--- /dev/null
+++ b/tests/ui/macros/die-macro.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(dead_code)]
+// Just testing that panic!() type checks in statement or expr
+
+
+#![allow(unreachable_code)]
+
+fn f() {
+    panic!();
+
+    let _x: isize = panic!();
+}
+
+pub fn main() {
+
+}
diff --git a/tests/ui/macros/doc-comment.rs b/tests/ui/macros/doc-comment.rs
new file mode 100644
index 00000000000..9de39e9b56c
--- /dev/null
+++ b/tests/ui/macros/doc-comment.rs
@@ -0,0 +1,25 @@
+// check-pass
+// Tests that we properly handle a nested macro expansion
+// involving a `#[doc]` attribute
+#![deny(missing_docs)]
+//! Crate docs
+
+macro_rules! doc_comment {
+    ($x:expr, $($tt:tt)*) => {
+        #[doc = $x]
+        $($tt)*
+    }
+}
+
+macro_rules! make_comment {
+    () => {
+        doc_comment!("Function docs",
+            pub fn bar() {}
+        );
+    }
+}
+
+
+make_comment!();
+
+fn main() {}
diff --git a/tests/ui/macros/dollar-crate-nested-encoding.rs b/tests/ui/macros/dollar-crate-nested-encoding.rs
new file mode 100644
index 00000000000..5242f7830bb
--- /dev/null
+++ b/tests/ui/macros/dollar-crate-nested-encoding.rs
@@ -0,0 +1,8 @@
+// check-pass
+// aux-build:dollar-crate-nested-encoding.rs
+
+extern crate dollar_crate_nested_encoding;
+
+type A = dollar_crate_nested_encoding::exported!();
+
+fn main() {}
diff --git a/tests/ui/macros/duplicate-builtin.rs b/tests/ui/macros/duplicate-builtin.rs
new file mode 100644
index 00000000000..35f0f429059
--- /dev/null
+++ b/tests/ui/macros/duplicate-builtin.rs
@@ -0,0 +1,17 @@
+// compile-flags:--crate-type lib
+#![feature(decl_macro)]
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+pub macro test($item:item) {
+//~^ NOTE previously defined
+    /* compiler built-in */
+}
+
+mod inner {
+    #[rustc_builtin_macro]
+    pub macro test($item:item) {
+    //~^ ERROR attempted to define built-in macro more than once [E0773]
+        /* compiler built-in */
+    }
+}
diff --git a/tests/ui/macros/duplicate-builtin.stderr b/tests/ui/macros/duplicate-builtin.stderr
new file mode 100644
index 00000000000..58accea27bb
--- /dev/null
+++ b/tests/ui/macros/duplicate-builtin.stderr
@@ -0,0 +1,21 @@
+error[E0773]: attempted to define built-in macro more than once
+  --> $DIR/duplicate-builtin.rs:13:5
+   |
+LL | /     pub macro test($item:item) {
+LL | |
+LL | |         /* compiler built-in */
+LL | |     }
+   | |_____^
+   |
+note: previously defined here
+  --> $DIR/duplicate-builtin.rs:6:1
+   |
+LL | / pub macro test($item:item) {
+LL | |
+LL | |     /* compiler built-in */
+LL | | }
+   | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0773`.
diff --git a/tests/ui/macros/edition-macro-pats.rs b/tests/ui/macros/edition-macro-pats.rs
new file mode 100644
index 00000000000..040894712a8
--- /dev/null
+++ b/tests/ui/macros/edition-macro-pats.rs
@@ -0,0 +1,12 @@
+// run-pass
+// edition:2021
+
+macro_rules! foo {
+    (a $x:pat_param) => {};
+    (b $x:pat) => {};
+}
+
+fn main() {
+    foo!(a None);
+    foo!(b 1 | 2);
+}
diff --git a/tests/ui/macros/empty-trailing-stmt.rs b/tests/ui/macros/empty-trailing-stmt.rs
new file mode 100644
index 00000000000..3d78ed4a475
--- /dev/null
+++ b/tests/ui/macros/empty-trailing-stmt.rs
@@ -0,0 +1,10 @@
+macro_rules! empty {
+    () => { }
+}
+
+fn foo() -> bool { //~ ERROR mismatched
+    { true } //~ ERROR mismatched
+    empty!();
+}
+
+fn main() {}
diff --git a/tests/ui/macros/empty-trailing-stmt.stderr b/tests/ui/macros/empty-trailing-stmt.stderr
new file mode 100644
index 00000000000..97a2edd3966
--- /dev/null
+++ b/tests/ui/macros/empty-trailing-stmt.stderr
@@ -0,0 +1,22 @@
+error[E0308]: mismatched types
+  --> $DIR/empty-trailing-stmt.rs:6:7
+   |
+LL |     { true }
+   |       ^^^^ expected `()`, found `bool`
+   |
+help: you might have meant to return this value
+   |
+LL |     { return true; }
+   |       ++++++     +
+
+error[E0308]: mismatched types
+  --> $DIR/empty-trailing-stmt.rs:5:13
+   |
+LL | fn foo() -> bool {
+   |    ---      ^^^^ expected `bool`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/macros/format-args-temporaries-async.rs b/tests/ui/macros/format-args-temporaries-async.rs
new file mode 100644
index 00000000000..d959329b9fc
--- /dev/null
+++ b/tests/ui/macros/format-args-temporaries-async.rs
@@ -0,0 +1,37 @@
+// check-pass
+// edition:2021
+
+use std::fmt::{self, Display};
+use std::future::Future;
+use std::io;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+struct AsyncStdout;
+
+impl AsyncStdout {
+    fn write_fmt<'a>(&'a mut self, _args: fmt::Arguments) -> WriteFmtFuture<'a, Self>
+    where
+        Self: Unpin,
+    {
+        WriteFmtFuture(self)
+    }
+}
+
+struct WriteFmtFuture<'a, T>(&'a mut T);
+
+impl<'a, T> Future for WriteFmtFuture<'a, T> {
+    type Output = io::Result<()>;
+    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+        unimplemented!()
+    }
+}
+
+async fn async_main() {
+    let _write = write!(&mut AsyncStdout, "...").await;
+    let _writeln = writeln!(&mut AsyncStdout, "...").await;
+}
+
+fn main() {
+    let _ = async_main;
+}
diff --git a/tests/ui/macros/format-args-temporaries-in-write.rs b/tests/ui/macros/format-args-temporaries-in-write.rs
new file mode 100644
index 00000000000..339ccbc33ac
--- /dev/null
+++ b/tests/ui/macros/format-args-temporaries-in-write.rs
@@ -0,0 +1,50 @@
+// check-fail
+
+use std::fmt::{self, Display};
+
+struct Mutex;
+
+impl Mutex {
+    fn lock(&self) -> MutexGuard {
+        MutexGuard(self)
+    }
+}
+
+struct MutexGuard<'a>(&'a Mutex);
+
+impl<'a> Drop for MutexGuard<'a> {
+    fn drop(&mut self) {
+        // Empty but this is a necessary part of the repro. Otherwise borrow
+        // checker is fine with 'a dangling at the time that MutexGuard goes out
+        // of scope.
+    }
+}
+
+struct Out;
+
+impl Out {
+    fn write_fmt(&self, _args: fmt::Arguments) {}
+}
+
+impl<'a> Display for MutexGuard<'a> {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        Ok(())
+    }
+}
+
+fn main() {
+    // FIXME(dtolnay): We actually want both of these to work. I think it's
+    // sadly unimplementable today though.
+
+    let _write = {
+        let mutex = Mutex;
+        write!(Out, "{}", mutex.lock()) /* no semicolon */
+        //~^ ERROR `mutex` does not live long enough
+    };
+
+    let _writeln = {
+        let mutex = Mutex;
+        writeln!(Out, "{}", mutex.lock()) /* no semicolon */
+        //~^ ERROR `mutex` does not live long enough
+    };
+}
diff --git a/tests/ui/macros/format-args-temporaries-in-write.stderr b/tests/ui/macros/format-args-temporaries-in-write.stderr
new file mode 100644
index 00000000000..287cd7d6704
--- /dev/null
+++ b/tests/ui/macros/format-args-temporaries-in-write.stderr
@@ -0,0 +1,33 @@
+error[E0597]: `mutex` does not live long enough
+  --> $DIR/format-args-temporaries-in-write.rs:41:27
+   |
+LL |         write!(Out, "{}", mutex.lock()) /* no semicolon */
+   |                           ^^^^^^^^^^^^
+   |                           |
+   |                           borrowed value does not live long enough
+   |                           a temporary with access to the borrow is created here ...
+LL |
+LL |     };
+   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
+   |     |
+   |     `mutex` dropped here while still borrowed
+   |
+
+error[E0597]: `mutex` does not live long enough
+  --> $DIR/format-args-temporaries-in-write.rs:47:29
+   |
+LL |         writeln!(Out, "{}", mutex.lock()) /* no semicolon */
+   |                             ^^^^^^^^^^^^
+   |                             |
+   |                             borrowed value does not live long enough
+   |                             a temporary with access to the borrow is created here ...
+LL |
+LL |     };
+   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
+   |     |
+   |     `mutex` dropped here while still borrowed
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/macros/format-args-temporaries.rs b/tests/ui/macros/format-args-temporaries.rs
new file mode 100644
index 00000000000..59323828bc3
--- /dev/null
+++ b/tests/ui/macros/format-args-temporaries.rs
@@ -0,0 +1,54 @@
+// check-pass
+
+use std::fmt::{self, Display};
+
+struct Mutex;
+
+impl Mutex {
+    fn lock(&self) -> MutexGuard {
+        MutexGuard(self)
+    }
+}
+
+struct MutexGuard<'a>(&'a Mutex);
+
+impl<'a> Drop for MutexGuard<'a> {
+    fn drop(&mut self) {
+        // Empty but this is a necessary part of the repro. Otherwise borrow
+        // checker is fine with 'a dangling at the time that MutexGuard goes out
+        // of scope.
+    }
+}
+
+impl<'a> Display for MutexGuard<'a> {
+    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
+        Ok(())
+    }
+}
+
+fn main() {
+    let _print = {
+        let mutex = Mutex;
+        print!("{}", mutex.lock()) /* no semicolon */
+    };
+
+    let _println = {
+        let mutex = Mutex;
+        println!("{}", mutex.lock()) /* no semicolon */
+    };
+
+    let _eprint = {
+        let mutex = Mutex;
+        eprint!("{}", mutex.lock()) /* no semicolon */
+    };
+
+    let _eprintln = {
+        let mutex = Mutex;
+        eprintln!("{}", mutex.lock()) /* no semicolon */
+    };
+
+    let _panic = {
+        let mutex = Mutex;
+        panic!("{}", mutex.lock()) /* no semicolon */
+    };
+}
diff --git a/tests/ui/macros/format-foreign.rs b/tests/ui/macros/format-foreign.rs
new file mode 100644
index 00000000000..ac65838f21d
--- /dev/null
+++ b/tests/ui/macros/format-foreign.rs
@@ -0,0 +1,17 @@
+fn main() {
+    println!("%.*3$s %s!\n", "Hello,", "World", 4); //~ ERROR multiple unused formatting arguments
+    println!("%1$*2$.*3$f", 123.456); //~ ERROR never used
+    println!(r###"%.*3$s
+        %s!\n
+"###, "Hello,", "World", 4);
+    //~^ ERROR multiple unused formatting arguments
+    // correctly account for raw strings in inline suggestions
+
+    // This should *not* produce hints, on the basis that there's equally as
+    // many "correct" format specifiers.  It's *probably* just an actual typo.
+    println!("{} %f", "one", 2.0); //~ ERROR never used
+
+    println!("Hi there, $NAME.", NAME="Tim"); //~ ERROR never used
+    println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
+    //~^ ERROR multiple unused formatting arguments
+}
diff --git a/tests/ui/macros/format-foreign.stderr b/tests/ui/macros/format-foreign.stderr
new file mode 100644
index 00000000000..7971c2ab2b9
--- /dev/null
+++ b/tests/ui/macros/format-foreign.stderr
@@ -0,0 +1,82 @@
+error: multiple unused formatting arguments
+  --> $DIR/format-foreign.rs:2:30
+   |
+LL |     println!("%.*3$s %s!\n", "Hello,", "World", 4);
+   |              --------------  ^^^^^^^^  ^^^^^^^  ^ argument never used
+   |              |               |         |
+   |              |               |         argument never used
+   |              |               argument never used
+   |              multiple missing formatting specifiers
+   |
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+help: format specifiers use curly braces
+   |
+LL |     println!("{:.2$} {}!\n", "Hello,", "World", 4);
+   |               ~~~~~~ ~~
+
+error: argument never used
+  --> $DIR/format-foreign.rs:3:29
+   |
+LL |     println!("%1$*2$.*3$f", 123.456);
+   |               -----------   ^^^^^^^ argument never used
+   |               |
+   |               help: format specifiers use curly braces: `{0:1$.2$}`
+   |
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: multiple unused formatting arguments
+  --> $DIR/format-foreign.rs:6:7
+   |
+LL |       println!(r###"%.*3$s
+   |  ______________-
+LL | |         %s!\n
+LL | | "###, "Hello,", "World", 4);
+   | |    -  ^^^^^^^^  ^^^^^^^  ^ argument never used
+   | |    |  |         |
+   | |    |  |         argument never used
+   | |____|  argument never used
+   |      multiple missing formatting specifiers
+   |
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+help: format specifiers use curly braces
+   |
+LL ~     println!(r###"{:.2$}
+LL ~         {}!\n
+   |
+
+error: argument never used
+  --> $DIR/format-foreign.rs:12:30
+   |
+LL |     println!("{} %f", "one", 2.0);
+   |              -------         ^^^ argument never used
+   |              |
+   |              formatting specifier missing
+
+error: named argument never used
+  --> $DIR/format-foreign.rs:14:39
+   |
+LL |     println!("Hi there, $NAME.", NAME="Tim");
+   |                         -----         ^^^^^ named argument never used
+   |                         |
+   |                         help: format specifiers use curly braces: `{NAME}`
+   |
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
+
+error: multiple unused formatting arguments
+  --> $DIR/format-foreign.rs:15:32
+   |
+LL |     println!("$1 $0 $$ $NAME", 1, 2, NAME=3);
+   |              ----------------  ^  ^       ^ named argument never used
+   |              |                 |  |
+   |              |                 |  argument never used
+   |              |                 argument never used
+   |              multiple missing formatting specifiers
+   |
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
+help: format specifiers use curly braces
+   |
+LL |     println!("{1} {0} $$ {NAME}", 1, 2, NAME=3);
+   |               ~~~ ~~~    ~~~~~~
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/macros/format-parse-errors.rs b/tests/ui/macros/format-parse-errors.rs
new file mode 100644
index 00000000000..ffa7a2817ff
--- /dev/null
+++ b/tests/ui/macros/format-parse-errors.rs
@@ -0,0 +1,17 @@
+fn main() {
+    let foo = "";
+    let bar = "";
+    format!(); //~ ERROR requires at least a format string argument
+    format!(struct); //~ ERROR expected expression
+    format!("s", name =); //~ ERROR expected expression
+    format!(
+        "s {foo} {} {}",
+        foo = foo,
+        bar, //~ ERROR positional arguments cannot follow named arguments
+    );
+    format!("s {foo}", foo = struct); //~ ERROR expected expression
+    format!("s", struct); //~ ERROR expected expression
+
+    // This error should come after parsing errors to ensure they are non-fatal.
+    format!(123); //~ ERROR format argument must be a string literal
+}
diff --git a/tests/ui/macros/format-parse-errors.stderr b/tests/ui/macros/format-parse-errors.stderr
new file mode 100644
index 00000000000..f9ea4c63377
--- /dev/null
+++ b/tests/ui/macros/format-parse-errors.stderr
@@ -0,0 +1,53 @@
+error: requires at least a format string argument
+  --> $DIR/format-parse-errors.rs:4:5
+   |
+LL |     format!();
+   |     ^^^^^^^^^
+   |
+   = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found keyword `struct`
+  --> $DIR/format-parse-errors.rs:5:13
+   |
+LL |     format!(struct);
+   |             ^^^^^^ expected expression
+
+error: expected expression, found end of macro arguments
+  --> $DIR/format-parse-errors.rs:6:24
+   |
+LL |     format!("s", name =);
+   |                        ^ expected expression
+
+error: positional arguments cannot follow named arguments
+  --> $DIR/format-parse-errors.rs:10:9
+   |
+LL |         foo = foo,
+   |         --------- named argument
+LL |         bar,
+   |         ^^^ positional arguments must be before named arguments
+
+error: expected expression, found keyword `struct`
+  --> $DIR/format-parse-errors.rs:12:30
+   |
+LL |     format!("s {foo}", foo = struct);
+   |                              ^^^^^^ expected expression
+
+error: expected expression, found keyword `struct`
+  --> $DIR/format-parse-errors.rs:13:18
+   |
+LL |     format!("s", struct);
+   |                  ^^^^^^ expected expression
+
+error: format argument must be a string literal
+  --> $DIR/format-parse-errors.rs:16:13
+   |
+LL |     format!(123);
+   |             ^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     format!("{}", 123);
+   |             +++++
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/macros/format-unused-lables.rs b/tests/ui/macros/format-unused-lables.rs
new file mode 100644
index 00000000000..56382b1011c
--- /dev/null
+++ b/tests/ui/macros/format-unused-lables.rs
@@ -0,0 +1,18 @@
+fn main() {
+    println!("Test", 123, 456, 789);
+    //~^ ERROR multiple unused formatting arguments
+
+    println!("Test2",
+        123,  //~ ERROR multiple unused formatting arguments
+        456,
+        789
+    );
+
+    println!("Some stuff", UNUSED="args"); //~ ERROR named argument never used
+
+    println!("Some more $STUFF",
+        "woo!",  //~ ERROR multiple unused formatting arguments
+            STUFF=
+       "things"
+             , UNUSED="args");
+}
diff --git a/tests/ui/macros/format-unused-lables.stderr b/tests/ui/macros/format-unused-lables.stderr
new file mode 100644
index 00000000000..fad87fa2aee
--- /dev/null
+++ b/tests/ui/macros/format-unused-lables.stderr
@@ -0,0 +1,50 @@
+error: multiple unused formatting arguments
+  --> $DIR/format-unused-lables.rs:2:22
+   |
+LL |     println!("Test", 123, 456, 789);
+   |              ------  ^^^  ^^^  ^^^ argument never used
+   |              |       |    |
+   |              |       |    argument never used
+   |              |       argument never used
+   |              multiple missing formatting specifiers
+
+error: multiple unused formatting arguments
+  --> $DIR/format-unused-lables.rs:6:9
+   |
+LL |     println!("Test2",
+   |              ------- multiple missing formatting specifiers
+LL |         123,
+   |         ^^^ argument never used
+LL |         456,
+   |         ^^^ argument never used
+LL |         789
+   |         ^^^ argument never used
+
+error: named argument never used
+  --> $DIR/format-unused-lables.rs:11:35
+   |
+LL |     println!("Some stuff", UNUSED="args");
+   |              ------------         ^^^^^^ named argument never used
+   |              |
+   |              formatting specifier missing
+
+error: multiple unused formatting arguments
+  --> $DIR/format-unused-lables.rs:14:9
+   |
+LL |     println!("Some more $STUFF",
+   |              ------------------
+   |              |          |
+   |              |          help: format specifiers use curly braces: `{STUFF}`
+   |              multiple missing formatting specifiers
+LL |         "woo!",
+   |         ^^^^^^ argument never used
+LL |             STUFF=
+LL |        "things"
+   |        ^^^^^^^^ named argument never used
+LL |              , UNUSED="args");
+   |                       ^^^^^^ named argument never used
+   |
+   = note: shell formatting is not supported; see the documentation for `std::fmt`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/global-asm.rs b/tests/ui/macros/global-asm.rs
new file mode 100644
index 00000000000..26e90edce0b
--- /dev/null
+++ b/tests/ui/macros/global-asm.rs
@@ -0,0 +1,7 @@
+use std::arch::global_asm;
+
+fn main() {
+    global_asm!(); //~ ERROR requires at least a template string argument
+    global_asm!(struct); //~ ERROR expected expression
+    global_asm!(123); //~ ERROR asm template must be a string literal
+}
diff --git a/tests/ui/macros/global-asm.stderr b/tests/ui/macros/global-asm.stderr
new file mode 100644
index 00000000000..3c26ec65aa2
--- /dev/null
+++ b/tests/ui/macros/global-asm.stderr
@@ -0,0 +1,20 @@
+error: requires at least a template string argument
+  --> $DIR/global-asm.rs:4:5
+   |
+LL |     global_asm!();
+   |     ^^^^^^^^^^^^^
+
+error: expected expression, found keyword `struct`
+  --> $DIR/global-asm.rs:5:17
+   |
+LL |     global_asm!(struct);
+   |                 ^^^^^^ expected expression
+
+error: asm template must be a string literal
+  --> $DIR/global-asm.rs:6:17
+   |
+LL |     global_asm!(123);
+   |                 ^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/html-literals.rs b/tests/ui/macros/html-literals.rs
new file mode 100644
index 00000000000..26f00fed9c4
--- /dev/null
+++ b/tests/ui/macros/html-literals.rs
@@ -0,0 +1,95 @@
+// run-pass
+
+#![allow(non_camel_case_types)]
+// A test of the macro system. Can we do HTML literals?
+
+/*
+
+This is an HTML parser written as a macro. It's all CPS, and we have
+to carry around a bunch of state. The arguments to macros all look like this:
+
+{ tag_stack* # expr* # tokens }
+
+The stack keeps track of where we are in the tree. The expr is a list
+of children of the current node. The tokens are everything that's
+left.
+
+*/
+use HTMLFragment::{tag, text};
+
+macro_rules! html {
+    ( $($body:tt)* ) => (
+        parse_node!( []; []; $($body)* )
+    )
+}
+
+macro_rules! parse_node {
+    (
+        [:$head:ident ($(:$head_nodes:expr),*)
+         $(:$tags:ident ($(:$tag_nodes:expr),*))*];
+        [$(:$nodes:expr),*];
+        </$tag:ident> $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$head_nodes,)* :tag(stringify!($head).to_string(),
+                                    vec![$($nodes),*])];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        <$tag:ident> $($rest:tt)*
+    ) => (
+        parse_node!(
+            [:$tag ($(:$nodes)*) $(: $tags ($(:$tag_nodes),*) )*];
+            [];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        . $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$nodes,)* :text(".".to_string())];
+            $($rest)*
+        )
+    );
+
+    (
+        [$(:$tags:ident ($(:$tag_nodes:expr),*) )*];
+        [$(:$nodes:expr),*];
+        $word:ident $($rest:tt)*
+    ) => (
+        parse_node!(
+            [$(: $tags ($(:$tag_nodes),*))*];
+            [$(:$nodes,)* :text(stringify!($word).to_string())];
+            $($rest)*
+        )
+    );
+
+    ( []; [:$e:expr]; ) => ( $e );
+}
+
+pub fn main() {
+    let _page = html! (
+        <html>
+            <head><title>This is the title.</title></head>
+            <body>
+            <p>This is some text</p>
+            </body>
+        </html>
+    );
+}
+
+#[allow(unused_tuple_struct_fields)]
+enum HTMLFragment {
+    tag(String, Vec<HTMLFragment> ),
+    text(String),
+}
diff --git a/tests/ui/macros/include-single-expr-helper-1.rs b/tests/ui/macros/include-single-expr-helper-1.rs
new file mode 100644
index 00000000000..aa6380bd24d
--- /dev/null
+++ b/tests/ui/macros/include-single-expr-helper-1.rs
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+
+// trailing comment permitted
diff --git a/tests/ui/macros/include-single-expr-helper.rs b/tests/ui/macros/include-single-expr-helper.rs
new file mode 100644
index 00000000000..84d8b69603b
--- /dev/null
+++ b/tests/ui/macros/include-single-expr-helper.rs
@@ -0,0 +1,5 @@
+// ignore-test auxiliary file for include-single-expr.rs
+
+0
+10
+100
diff --git a/tests/ui/macros/include-single-expr.rs b/tests/ui/macros/include-single-expr.rs
new file mode 100644
index 00000000000..0f4c29ec014
--- /dev/null
+++ b/tests/ui/macros/include-single-expr.rs
@@ -0,0 +1,6 @@
+// error-pattern include macro expected single expression
+
+fn main() {
+    include!("include-single-expr-helper.rs");
+    include!("include-single-expr-helper-1.rs");
+}
diff --git a/tests/ui/macros/include-single-expr.stderr b/tests/ui/macros/include-single-expr.stderr
new file mode 100644
index 00000000000..80eecf8f1b9
--- /dev/null
+++ b/tests/ui/macros/include-single-expr.stderr
@@ -0,0 +1,10 @@
+error: include macro expected single expression in source
+  --> $DIR/include-single-expr-helper.rs:4:1
+   |
+LL | 10
+   | ^^
+   |
+   = note: `#[deny(incomplete_include)]` on by default
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-100199.rs b/tests/ui/macros/issue-100199.rs
new file mode 100644
index 00000000000..6e50afa0759
--- /dev/null
+++ b/tests/ui/macros/issue-100199.rs
@@ -0,0 +1,16 @@
+#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root
+struct Foo {}
+// The above must be on the first line so that it's span points to pos 0.
+// This used to trigger an ICE because the diagnostic emitter would get
+// an unexpected dummy span (lo == 0 == hi) while attempting to print a
+// suggestion.
+
+// aux-build: issue-100199.rs
+
+extern crate issue_100199;
+
+mod traits {
+    pub trait MyTrait {}
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-100199.stderr b/tests/ui/macros/issue-100199.stderr
new file mode 100644
index 00000000000..2cb45dc1247
--- /dev/null
+++ b/tests/ui/macros/issue-100199.stderr
@@ -0,0 +1,15 @@
+error[E0405]: cannot find trait `MyTrait` in the crate root
+  --> $DIR/issue-100199.rs:1:1
+   |
+LL | #[issue_100199::struct_with_bound]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root
+   |
+   = note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider importing this trait
+   |
+LL | use traits::MyTrait;
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0405`.
diff --git a/tests/ui/macros/issue-102878.rs b/tests/ui/macros/issue-102878.rs
new file mode 100644
index 00000000000..aac5891939e
--- /dev/null
+++ b/tests/ui/macros/issue-102878.rs
@@ -0,0 +1,10 @@
+macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+//~^ ERROR mismatched closing delimiter: `)`
+//~| ERROR invalid fragment specifier `r`
+//~| ERROR expected identifier, found keyword `const`
+//~| ERROR expected identifier, found keyword `const`
+//~| ERROR expected identifier, found `:`
+
+fn s(){test!(1,i)}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-102878.stderr b/tests/ui/macros/issue-102878.stderr
new file mode 100644
index 00000000000..e0b8855a38d
--- /dev/null
+++ b/tests/ui/macros/issue-102878.stderr
@@ -0,0 +1,60 @@
+error: mismatched closing delimiter: `)`
+  --> $DIR/issue-102878.rs:1:35
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                  -^         ^ mismatched closing delimiter
+   |                                  ||
+   |                                  |unclosed delimiter
+   |                                  closing delimiter possibly meant for this
+
+error: invalid fragment specifier `r`
+  --> $DIR/issue-102878.rs:1:27
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                           ^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: expected identifier, found keyword `const`
+  --> $DIR/issue-102878.rs:1:36
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                    ^^^^^ expected identifier, found keyword
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: escape `const` to use it as an identifier
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
+   |                                    ++
+
+error: expected identifier, found keyword `const`
+  --> $DIR/issue-102878.rs:1:36
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                    ^^^^^ expected identifier, found keyword
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: escape `const` to use it as an identifier
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)}
+   |                                    ++
+
+error: expected identifier, found `:`
+  --> $DIR/issue-102878.rs:1:41
+   |
+LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)}
+   |                                         ^ expected identifier
+...
+LL | fn s(){test!(1,i)}
+   |        ---------- in this macro invocation
+   |
+   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/macros/issue-103529.rs b/tests/ui/macros/issue-103529.rs
new file mode 100644
index 00000000000..fa05baed7fc
--- /dev/null
+++ b/tests/ui/macros/issue-103529.rs
@@ -0,0 +1,13 @@
+macro_rules! m {
+    ($s:stmt) => {}
+}
+
+m! { mut x }
+//~^ ERROR expected expression, found keyword `mut`
+//~| ERROR expected a statement
+m! { auto x }
+//~^ ERROR invalid variable declaration
+m! { var x }
+//~^ ERROR invalid variable declaration
+
+fn main() {}
diff --git a/tests/ui/macros/issue-103529.stderr b/tests/ui/macros/issue-103529.stderr
new file mode 100644
index 00000000000..61e322afc77
--- /dev/null
+++ b/tests/ui/macros/issue-103529.stderr
@@ -0,0 +1,39 @@
+error: expected expression, found keyword `mut`
+  --> $DIR/issue-103529.rs:5:6
+   |
+LL | m! { mut x }
+   |      ^^^ expected expression
+
+error: expected a statement
+  --> $DIR/issue-103529.rs:5:10
+   |
+LL |     ($s:stmt) => {}
+   |      ------- while parsing argument for this `stmt` macro fragment
+...
+LL | m! { mut x }
+   |          ^
+
+error: invalid variable declaration
+  --> $DIR/issue-103529.rs:8:6
+   |
+LL | m! { auto x }
+   |      ^^^^
+   |
+help: write `let` instead of `auto` to introduce a new variable
+   |
+LL | m! { let x }
+   |      ~~~
+
+error: invalid variable declaration
+  --> $DIR/issue-103529.rs:10:6
+   |
+LL | m! { var x }
+   |      ^^^
+   |
+help: write `let` instead of `var` to introduce a new variable
+   |
+LL | m! { let x }
+   |      ~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs
new file mode 100644
index 00000000000..24150376ef0
--- /dev/null
+++ b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.rs
@@ -0,0 +1,8 @@
+#![feature(concat_bytes)]
+
+fn main() {
+    concat_bytes!(7Y);
+    //~^ ERROR invalid suffix `Y` for number literal
+    concat_bytes!(888888888888888888888888888888888888888);
+    //~^ ERROR integer literal is too large
+}
diff --git a/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr
new file mode 100644
index 00000000000..8807279c27f
--- /dev/null
+++ b/tests/ui/macros/issue-104769-concat_bytes-invalid-literal.stderr
@@ -0,0 +1,18 @@
+error: invalid suffix `Y` for number literal
+  --> $DIR/issue-104769-concat_bytes-invalid-literal.rs:4:19
+   |
+LL |     concat_bytes!(7Y);
+   |                   ^^ invalid suffix `Y`
+   |
+   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+error: integer literal is too large
+  --> $DIR/issue-104769-concat_bytes-invalid-literal.rs:6:19
+   |
+LL |     concat_bytes!(888888888888888888888888888888888888888);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: value exceeds limit of `340282366920938463463374607431768211455`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-105011.rs b/tests/ui/macros/issue-105011.rs
new file mode 100644
index 00000000000..da12c381464
--- /dev/null
+++ b/tests/ui/macros/issue-105011.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!(""y); //~ ERROR suffixes on string literals are invalid
+}
diff --git a/tests/ui/macros/issue-105011.stderr b/tests/ui/macros/issue-105011.stderr
new file mode 100644
index 00000000000..e898af7faa3
--- /dev/null
+++ b/tests/ui/macros/issue-105011.stderr
@@ -0,0 +1,8 @@
+error: suffixes on string literals are invalid
+  --> $DIR/issue-105011.rs:2:14
+   |
+LL |     println!(""y);
+   |              ^^^ invalid suffix `y`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-10536.rs b/tests/ui/macros/issue-10536.rs
new file mode 100644
index 00000000000..f536d8f940a
--- /dev/null
+++ b/tests/ui/macros/issue-10536.rs
@@ -0,0 +1,19 @@
+// We only want to assert that this doesn't ICE, we don't particularly care
+// about whether it nor it fails to compile.
+
+macro_rules! foo{
+    () => {{
+        macro_rules! bar{() => (())}
+        1
+    }}
+}
+
+pub fn main() {
+    foo!();
+
+    assert!({one! two()}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+
+    // regardless of whether nested macro_rules works, the following should at
+    // least throw a conventional error.
+    assert!({one! two}); //~ ERROR expected one of `(`, `[`, or `{`, found `two`
+}
diff --git a/tests/ui/macros/issue-10536.stderr b/tests/ui/macros/issue-10536.stderr
new file mode 100644
index 00000000000..cc048445871
--- /dev/null
+++ b/tests/ui/macros/issue-10536.stderr
@@ -0,0 +1,14 @@
+error: expected one of `(`, `[`, or `{`, found `two`
+  --> $DIR/issue-10536.rs:14:19
+   |
+LL |     assert!({one! two()});
+   |                   ^^^ expected one of `(`, `[`, or `{`
+
+error: expected one of `(`, `[`, or `{`, found `two`
+  --> $DIR/issue-10536.rs:18:19
+   |
+LL |     assert!({one! two});
+   |                   ^^^ expected one of `(`, `[`, or `{`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-16098.rs b/tests/ui/macros/issue-16098.rs
new file mode 100644
index 00000000000..00acc20fc9e
--- /dev/null
+++ b/tests/ui/macros/issue-16098.rs
@@ -0,0 +1,16 @@
+macro_rules! prob1 {
+    (0) => {
+        0
+    };
+    ($n:expr) => {
+        if ($n % 3 == 0) || ($n % 5 == 0) {
+            $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
+        } else {
+            prob1!($n - 1);
+        }
+    };
+}
+
+fn main() {
+    println!("Problem 1: {}", prob1!(1000));
+}
diff --git a/tests/ui/macros/issue-16098.stderr b/tests/ui/macros/issue-16098.stderr
new file mode 100644
index 00000000000..64280219d75
--- /dev/null
+++ b/tests/ui/macros/issue-16098.stderr
@@ -0,0 +1,14 @@
+error: recursion limit reached while expanding `prob1!`
+  --> $DIR/issue-16098.rs:7:18
+   |
+LL |             $n + prob1!($n - 1);
+   |                  ^^^^^^^^^^^^^^
+...
+LL |     println!("Problem 1: {}", prob1!(1000));
+   |                               ------------ in this macro invocation
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`)
+   = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-19163.rs b/tests/ui/macros/issue-19163.rs
new file mode 100644
index 00000000000..d98c5912af2
--- /dev/null
+++ b/tests/ui/macros/issue-19163.rs
@@ -0,0 +1,11 @@
+// aux-build:issue-19163.rs
+
+#[macro_use] extern crate issue_19163;
+
+use std::io::Write;
+
+fn main() {
+    let mut v = vec![];
+    mywrite!(&v, "Hello world");
+    //~^ ERROR cannot borrow data in a `&` reference as mutable
+}
diff --git a/tests/ui/macros/issue-19163.stderr b/tests/ui/macros/issue-19163.stderr
new file mode 100644
index 00000000000..ae1ae14266f
--- /dev/null
+++ b/tests/ui/macros/issue-19163.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/issue-19163.rs:9:5
+   |
+LL |     mywrite!(&v, "Hello world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+   |
+   = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/macros/issue-21356.rs b/tests/ui/macros/issue-21356.rs
new file mode 100644
index 00000000000..ae623929d63
--- /dev/null
+++ b/tests/ui/macros/issue-21356.rs
@@ -0,0 +1,6 @@
+#![allow(unused_macros)]
+
+macro_rules! test { ($wrong:t_ty ..) => () }
+                  //~^ ERROR: invalid fragment specifier `t_ty`
+
+fn main() {}
diff --git a/tests/ui/macros/issue-21356.stderr b/tests/ui/macros/issue-21356.stderr
new file mode 100644
index 00000000000..17014c6ceee
--- /dev/null
+++ b/tests/ui/macros/issue-21356.stderr
@@ -0,0 +1,10 @@
+error: invalid fragment specifier `t_ty`
+  --> $DIR/issue-21356.rs:3:22
+   |
+LL | macro_rules! test { ($wrong:t_ty ..) => () }
+   |                      ^^^^^^^^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-22463.rs b/tests/ui/macros/issue-22463.rs
new file mode 100644
index 00000000000..fdf5a2fca72
--- /dev/null
+++ b/tests/ui/macros/issue-22463.rs
@@ -0,0 +1,20 @@
+// run-pass
+macro_rules! items {
+    () => {
+        type A = ();
+        fn a() {}
+    }
+}
+
+trait Foo {
+    type A;
+    fn a();
+}
+
+impl Foo for () {
+    items!();
+}
+
+fn main() {
+
+}
diff --git a/tests/ui/macros/issue-25274.rs b/tests/ui/macros/issue-25274.rs
new file mode 100644
index 00000000000..65b29bba8c8
--- /dev/null
+++ b/tests/ui/macros/issue-25274.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+macro_rules! test {
+    (
+        fn fun() -> Option<Box<$t:ty>>;
+    ) => {
+        fn fun(x: $t) -> Option<Box<$t>>
+        { Some(Box::new(x)) }
+    }
+}
+
+test! {
+    fn fun() -> Option<Box<i32>>;
+}
+
+fn main() {
+    println!("{}", fun(0).unwrap());
+}
diff --git a/tests/ui/macros/issue-25385.rs b/tests/ui/macros/issue-25385.rs
new file mode 100644
index 00000000000..ea042a6c76b
--- /dev/null
+++ b/tests/ui/macros/issue-25385.rs
@@ -0,0 +1,12 @@
+macro_rules! foo {
+    ($e:expr) => { $e.foo() }
+    //~^ ERROR no method named `foo` found
+}
+
+fn main() {
+    let a = 1i32;
+    foo!(a);
+
+    foo!(1i32.foo());
+    //~^ ERROR no method named `foo` found
+}
diff --git a/tests/ui/macros/issue-25385.stderr b/tests/ui/macros/issue-25385.stderr
new file mode 100644
index 00000000000..39dbdd753a6
--- /dev/null
+++ b/tests/ui/macros/issue-25385.stderr
@@ -0,0 +1,20 @@
+error[E0599]: no method named `foo` found for type `i32` in the current scope
+  --> $DIR/issue-25385.rs:2:23
+   |
+LL |     ($e:expr) => { $e.foo() }
+   |                       ^^^ method not found in `i32`
+...
+LL |     foo!(a);
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0599]: no method named `foo` found for type `i32` in the current scope
+  --> $DIR/issue-25385.rs:10:15
+   |
+LL |     foo!(1i32.foo());
+   |               ^^^ method not found in `i32`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/macros/issue-26322.rs b/tests/ui/macros/issue-26322.rs
new file mode 100644
index 00000000000..c1dc80eb7c5
--- /dev/null
+++ b/tests/ui/macros/issue-26322.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+macro_rules! columnline {
+    () => (
+        (column!(), line!())
+    )
+}
+
+macro_rules! indirectcolumnline {
+    () => (
+        (||{ columnline!() })()
+    )
+}
+
+fn main() {
+    let closure = || {
+        columnline!()
+    };
+    let iflet = if let Some(_) = Some(0) {
+        columnline!()
+    } else { (0, 0) };
+    let cl = columnline!();
+    assert_eq!(closure(), (9, 19));
+    assert_eq!(iflet, (9, 22));
+    assert_eq!(cl, (14, 24));
+    let indirect = indirectcolumnline!();
+    assert_eq!(indirect, (20, 28));
+}
diff --git a/tests/ui/macros/issue-29084.rs b/tests/ui/macros/issue-29084.rs
new file mode 100644
index 00000000000..d1625268669
--- /dev/null
+++ b/tests/ui/macros/issue-29084.rs
@@ -0,0 +1,13 @@
+macro_rules! foo {
+    ($d:expr) => {{
+        fn bar(d: u8) { }
+        bar(&mut $d);
+        //~^ ERROR mismatched types
+        //~| expected `u8`, found `&mut u8`
+    }}
+}
+
+fn main() {
+    foo!(0u8);
+    //~^ in this expansion of foo!
+}
diff --git a/tests/ui/macros/issue-29084.stderr b/tests/ui/macros/issue-29084.stderr
new file mode 100644
index 00000000000..f83e192130b
--- /dev/null
+++ b/tests/ui/macros/issue-29084.stderr
@@ -0,0 +1,24 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-29084.rs:4:13
+   |
+LL |         bar(&mut $d);
+   |         --- ^^^^^^^ expected `u8`, found `&mut u8`
+   |         |
+   |         arguments to this function are incorrect
+...
+LL |     foo!(0u8);
+   |     --------- in this macro invocation
+   |
+note: function defined here
+  --> $DIR/issue-29084.rs:3:12
+   |
+LL |         fn bar(d: u8) { }
+   |            ^^^ -----
+...
+LL |     foo!(0u8);
+   |     --------- in this macro invocation
+   = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/macros/issue-30143.rs b/tests/ui/macros/issue-30143.rs
new file mode 100644
index 00000000000..ac4c1da5cb7
--- /dev/null
+++ b/tests/ui/macros/issue-30143.rs
@@ -0,0 +1,11 @@
+use std::fmt::Write;
+
+fn main() {
+    println!(0);
+    //~^ ERROR format argument must be a string literal
+    eprintln!('a');
+    //~^ ERROR format argument must be a string literal
+    let mut s = String::new();
+    writeln!(s, true).unwrap();
+    //~^ ERROR format argument must be a string literal
+}
diff --git a/tests/ui/macros/issue-30143.stderr b/tests/ui/macros/issue-30143.stderr
new file mode 100644
index 00000000000..fd2378dbcb3
--- /dev/null
+++ b/tests/ui/macros/issue-30143.stderr
@@ -0,0 +1,35 @@
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:4:14
+   |
+LL |     println!(0);
+   |              ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     println!("{}", 0);
+   |              +++++
+
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:6:15
+   |
+LL |     eprintln!('a');
+   |               ^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     eprintln!("{}", 'a');
+   |               +++++
+
+error: format argument must be a string literal
+  --> $DIR/issue-30143.rs:9:17
+   |
+LL |     writeln!(s, true).unwrap();
+   |                 ^^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     writeln!(s, "{}", true).unwrap();
+   |                 +++++
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/issue-33185.rs b/tests/ui/macros/issue-33185.rs
new file mode 100644
index 00000000000..0d6669146a6
--- /dev/null
+++ b/tests/ui/macros/issue-33185.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(dead_code)]
+
+#[macro_export]
+macro_rules! state {
+    ( $( $name:ident : $field:ty )* ) => (
+        #[derive(Default)]
+        struct State {
+            $($name : $field),*
+        }
+    )
+}
+
+state! { x: i64 }
+
+pub fn main() {
+}
diff --git a/tests/ui/macros/issue-34171.rs b/tests/ui/macros/issue-34171.rs
new file mode 100644
index 00000000000..157c58c459d
--- /dev/null
+++ b/tests/ui/macros/issue-34171.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+macro_rules! null { ($i:tt) => {} }
+macro_rules! apply_null {
+    ($i:item) => { null! { $i } }
+}
+
+fn main() {
+    apply_null!(#[cfg(all())] fn f() {});
+}
diff --git a/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs
new file mode 100644
index 00000000000..d7813936554
--- /dev/null
+++ b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs
@@ -0,0 +1,15 @@
+macro_rules! make_item {
+    ($a:ident) => {
+        struct $a;
+    }; //~^ ERROR expected expression
+       //~| ERROR expected expression
+}
+
+fn a() {
+    make_item!(A)
+}
+fn b() {
+    make_item!(B)
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr
new file mode 100644
index 00000000000..00139662d61
--- /dev/null
+++ b/tests/ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.stderr
@@ -0,0 +1,34 @@
+error: expected expression, found keyword `struct`
+  --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9
+   |
+LL |         struct $a;
+   |         ^^^^^^ expected expression
+...
+LL |     make_item!(A)
+   |     ------------- in this macro invocation
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+   = note: this error originates in the macro `make_item` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `;` to interpret the expansion as a statement
+   |
+LL |     make_item!(A);
+   |                  +
+
+error: expected expression, found keyword `struct`
+  --> $DIR/issue-34421-mac-expr-bad-stmt-good-add-semi.rs:3:9
+   |
+LL |         struct $a;
+   |         ^^^^^^ expected expression
+...
+LL |     make_item!(B)
+   |     ------------- in this macro invocation
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+   = note: this error originates in the macro `make_item` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: add `;` to interpret the expansion as a statement
+   |
+LL |     make_item!(B);
+   |                  +
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-35450.rs b/tests/ui/macros/issue-35450.rs
new file mode 100644
index 00000000000..ac4c16306cd
--- /dev/null
+++ b/tests/ui/macros/issue-35450.rs
@@ -0,0 +1,5 @@
+macro_rules! m { ($($t:tt)*) => { $($t)* } }
+
+fn main() {
+    m!($t); //~ ERROR expected expression
+}
diff --git a/tests/ui/macros/issue-35450.stderr b/tests/ui/macros/issue-35450.stderr
new file mode 100644
index 00000000000..f2065689f44
--- /dev/null
+++ b/tests/ui/macros/issue-35450.stderr
@@ -0,0 +1,8 @@
+error: expected expression, found `$`
+  --> $DIR/issue-35450.rs:4:8
+   |
+LL |     m!($t);
+   |        ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-37175.rs b/tests/ui/macros/issue-37175.rs
new file mode 100644
index 00000000000..9ec9d48d18b
--- /dev/null
+++ b/tests/ui/macros/issue-37175.rs
@@ -0,0 +1,5 @@
+// run-pass
+macro_rules! m { (<$t:ty>) => { stringify!($t) } }
+fn main() {
+    println!("{}", m!(<Vec<i32>>));
+}
diff --git a/tests/ui/macros/issue-38715.rs b/tests/ui/macros/issue-38715.rs
new file mode 100644
index 00000000000..85ed97663e8
--- /dev/null
+++ b/tests/ui/macros/issue-38715.rs
@@ -0,0 +1,17 @@
+#[macro_export]
+macro_rules! foo { () => {} }
+
+#[macro_export]
+macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
+
+mod inner1 {
+    #[macro_export]
+    macro_rules! bar { () => {} }
+}
+
+mod inner2 {
+    #[macro_export]
+    macro_rules! bar { () => {} } //~ ERROR the name `bar` is defined multiple times
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-38715.stderr b/tests/ui/macros/issue-38715.stderr
new file mode 100644
index 00000000000..828a7f45930
--- /dev/null
+++ b/tests/ui/macros/issue-38715.stderr
@@ -0,0 +1,25 @@
+error[E0428]: the name `foo` is defined multiple times
+  --> $DIR/issue-38715.rs:5:1
+   |
+LL | macro_rules! foo { () => {} }
+   | ---------------- previous definition of the macro `foo` here
+...
+LL | macro_rules! foo { () => {} }
+   | ^^^^^^^^^^^^^^^^ `foo` redefined here
+   |
+   = note: `foo` must be defined only once in the macro namespace of this module
+
+error[E0428]: the name `bar` is defined multiple times
+  --> $DIR/issue-38715.rs:14:5
+   |
+LL |     macro_rules! bar { () => {} }
+   |     ---------------- previous definition of the macro `bar` here
+...
+LL |     macro_rules! bar { () => {} }
+   |     ^^^^^^^^^^^^^^^^ `bar` redefined here
+   |
+   = note: `bar` must be defined only once in the macro namespace of this module
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui/macros/issue-39388.rs b/tests/ui/macros/issue-39388.rs
new file mode 100644
index 00000000000..a8e31a648c9
--- /dev/null
+++ b/tests/ui/macros/issue-39388.rs
@@ -0,0 +1,9 @@
+#![allow(unused_macros)]
+
+macro_rules! assign {
+    (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?`
+        $($a)* = $($b)*
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-39388.stderr b/tests/ui/macros/issue-39388.stderr
new file mode 100644
index 00000000000..62e7dff5476
--- /dev/null
+++ b/tests/ui/macros/issue-39388.stderr
@@ -0,0 +1,8 @@
+error: expected one of: `*`, `+`, or `?`
+  --> $DIR/issue-39388.rs:4:22
+   |
+LL |     (($($a:tt)*) = ($($b:tt))*) => {
+   |                      ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs
new file mode 100644
index 00000000000..2229f2c3900
--- /dev/null
+++ b/tests/ui/macros/issue-39404.rs
@@ -0,0 +1,7 @@
+#![allow(unused)]
+
+macro_rules! m { ($i) => {} }
+//~^ ERROR missing fragment specifier
+//~| WARN previously accepted
+
+fn main() {}
diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr
new file mode 100644
index 00000000000..3886a70bb15
--- /dev/null
+++ b/tests/ui/macros/issue-39404.stderr
@@ -0,0 +1,12 @@
+error: missing fragment specifier
+  --> $DIR/issue-39404.rs:3:19
+   |
+LL | macro_rules! m { ($i) => {} }
+   |                   ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-40469.rs b/tests/ui/macros/issue-40469.rs
new file mode 100644
index 00000000000..25e08ef85e9
--- /dev/null
+++ b/tests/ui/macros/issue-40469.rs
@@ -0,0 +1,9 @@
+// run-pass
+// ignore-pretty issue #37195
+
+#![allow(dead_code)]
+
+include!("auxiliary/issue-40469.rs");
+fn f() { m!(); }
+
+fn main() {}
diff --git a/tests/ui/macros/issue-40770.rs b/tests/ui/macros/issue-40770.rs
new file mode 100644
index 00000000000..c9713c15798
--- /dev/null
+++ b/tests/ui/macros/issue-40770.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![allow(unused_macros)]
+macro_rules! m {
+    ($e:expr) => {
+        macro_rules! n { () => { $e } }
+    }
+}
+
+fn main() {
+    m!(foo!());
+}
diff --git a/tests/ui/macros/issue-41776.rs b/tests/ui/macros/issue-41776.rs
new file mode 100644
index 00000000000..24696d86d0f
--- /dev/null
+++ b/tests/ui/macros/issue-41776.rs
@@ -0,0 +1,3 @@
+fn main() {
+    include!(line!()); //~ ERROR argument must be a string literal
+}
diff --git a/tests/ui/macros/issue-41776.stderr b/tests/ui/macros/issue-41776.stderr
new file mode 100644
index 00000000000..e06873b5026
--- /dev/null
+++ b/tests/ui/macros/issue-41776.stderr
@@ -0,0 +1,8 @@
+error: argument must be a string literal
+  --> $DIR/issue-41776.rs:2:14
+   |
+LL |     include!(line!());
+   |              ^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-41803.rs b/tests/ui/macros/issue-41803.rs
new file mode 100644
index 00000000000..bccfdc61146
--- /dev/null
+++ b/tests/ui/macros/issue-41803.rs
@@ -0,0 +1,23 @@
+// run-pass
+#![allow(unused_macro_rules)]
+
+/// A compile-time map from identifiers to arbitrary (heterogeneous) expressions
+macro_rules! ident_map {
+    ( $name:ident = { $($key:ident => $e:expr,)* } ) => {
+        macro_rules! $name {
+            $(
+                ( $key ) => { $e };
+            )*
+            // Empty invocation expands to nothing. Needed when the map is empty.
+            () => {};
+        }
+    };
+}
+
+ident_map!(my_map = {
+    main => 0,
+});
+
+fn main() {
+    my_map!(main);
+}
diff --git a/tests/ui/macros/issue-42954.fixed b/tests/ui/macros/issue-42954.fixed
new file mode 100644
index 00000000000..a73054c9257
--- /dev/null
+++ b/tests/ui/macros/issue-42954.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(unused_must_use, unused_comparisons)]
+
+macro_rules! is_plainly_printable {
+    ($i: ident) => {
+        ($i as u32) < 0 //~ `<` is interpreted as a start of generic arguments
+    };
+}
+
+fn main() {
+    let c = 'a';
+    is_plainly_printable!(c);
+}
diff --git a/tests/ui/macros/issue-42954.rs b/tests/ui/macros/issue-42954.rs
new file mode 100644
index 00000000000..5f9b0e31da5
--- /dev/null
+++ b/tests/ui/macros/issue-42954.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![allow(unused_must_use, unused_comparisons)]
+
+macro_rules! is_plainly_printable {
+    ($i: ident) => {
+        $i as u32 < 0 //~ `<` is interpreted as a start of generic arguments
+    };
+}
+
+fn main() {
+    let c = 'a';
+    is_plainly_printable!(c);
+}
diff --git a/tests/ui/macros/issue-42954.stderr b/tests/ui/macros/issue-42954.stderr
new file mode 100644
index 00000000000..396a91994eb
--- /dev/null
+++ b/tests/ui/macros/issue-42954.stderr
@@ -0,0 +1,19 @@
+error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison
+  --> $DIR/issue-42954.rs:7:19
+   |
+LL |         $i as u32 < 0
+   |                   ^ - interpreted as generic arguments
+   |                   |
+   |                   not interpreted as comparison
+...
+LL |     is_plainly_printable!(c);
+   |     ------------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `is_plainly_printable` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: try comparing the cast value
+   |
+LL |         ($i as u32) < 0
+   |         +         +
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-44127.rs b/tests/ui/macros/issue-44127.rs
new file mode 100644
index 00000000000..21b2e68264a
--- /dev/null
+++ b/tests/ui/macros/issue-44127.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+#![feature(decl_macro)]
+
+pub struct Foo {
+    bar: u32,
+}
+pub macro pattern($a:pat) {
+    Foo { bar: $a }
+}
+
+fn main() {
+    match (Foo { bar: 3 }) {
+        pattern!(3) => println!("Test OK"),
+        _ => unreachable!(),
+    }
+}
diff --git a/tests/ui/macros/issue-5060.rs b/tests/ui/macros/issue-5060.rs
new file mode 100644
index 00000000000..c4760bc029b
--- /dev/null
+++ b/tests/ui/macros/issue-5060.rs
@@ -0,0 +1,16 @@
+// run-pass
+macro_rules! print_hd_tl {
+    ($field_hd:ident, $($field_tl:ident),+) => ({
+        print!("{}", stringify!($field_hd));
+        print!("::[");
+        $(
+            print!("{}", stringify!($field_tl));
+            print!(", ");
+        )+
+        print!("]\n");
+    })
+}
+
+pub fn main() {
+    print_hd_tl!(x, y, z, w)
+}
diff --git a/tests/ui/macros/issue-51848.rs b/tests/ui/macros/issue-51848.rs
new file mode 100644
index 00000000000..4792bdd64f0
--- /dev/null
+++ b/tests/ui/macros/issue-51848.rs
@@ -0,0 +1,20 @@
+// In case of macro expansion, the errors should be matched using the deepest callsite in the
+// macro call stack whose span is in the current file
+
+macro_rules! macro_with_error {
+    ( ) => {
+        println!("{"); //~ ERROR invalid
+    };
+}
+
+fn foo() {
+
+}
+
+fn main() {
+    macro_with_error!();
+    //^ In case of a local macro we want the error to be matched in the macro definition, not here
+
+    println!("}"); //~ ERROR invalid
+    //^ In case of an external macro we want the error to be matched here
+}
diff --git a/tests/ui/macros/issue-51848.stderr b/tests/ui/macros/issue-51848.stderr
new file mode 100644
index 00000000000..c25bedf37b7
--- /dev/null
+++ b/tests/ui/macros/issue-51848.stderr
@@ -0,0 +1,24 @@
+error: invalid format string: expected `'}'` but string was terminated
+  --> $DIR/issue-51848.rs:6:20
+   |
+LL |         println!("{");
+   |                   -^ expected `'}'` in format string
+   |                   |
+   |                   because of this opening brace
+...
+LL |     macro_with_error!();
+   |     ------------------- in this macro invocation
+   |
+   = note: if you intended to print `{`, you can escape it using `{{`
+   = note: this error originates in the macro `macro_with_error` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: invalid format string: unmatched `}` found
+  --> $DIR/issue-51848.rs:18:15
+   |
+LL |     println!("}");
+   |               ^ unmatched `}` in format string
+   |
+   = note: if you intended to print `}`, you can escape it using `}}`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-52169.rs b/tests/ui/macros/issue-52169.rs
new file mode 100644
index 00000000000..f178cd30cb4
--- /dev/null
+++ b/tests/ui/macros/issue-52169.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#[allow(unused_macro_rules)]
+macro_rules! a {
+    ($i:literal) => { "right" };
+    ($i:tt) => { "wrong" };
+}
+
+macro_rules! b {
+    ($i:literal) => { a!($i) };
+}
+
+fn main() {
+    assert_eq!(b!(0), "right");
+}
diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs
new file mode 100644
index 00000000000..b24d7e1f6be
--- /dev/null
+++ b/tests/ui/macros/issue-54441.rs
@@ -0,0 +1,11 @@
+macro_rules! m {
+    () => {
+        let //~ ERROR macro expansion ignores token `let` and any following
+    };
+}
+
+extern "C" {
+    m!();
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr
new file mode 100644
index 00000000000..bbbca211b8d
--- /dev/null
+++ b/tests/ui/macros/issue-54441.stderr
@@ -0,0 +1,13 @@
+error: macro expansion ignores token `let` and any following
+  --> $DIR/issue-54441.rs:3:9
+   |
+LL |         let
+   |         ^^^
+...
+LL |     m!();
+   |     ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in foreign item context
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-57597.rs b/tests/ui/macros/issue-57597.rs
new file mode 100644
index 00000000000..ebeb3fe07ad
--- /dev/null
+++ b/tests/ui/macros/issue-57597.rs
@@ -0,0 +1,80 @@
+// Regression test for #57597.
+//
+// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
+
+// edition:2018
+
+macro_rules! foo1 {
+    ($($($i:ident)?)+) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo2 {
+    ($($($i:ident)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo3 {
+    ($($($i:ident)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo4 {
+    ($($($($i:ident)?)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo5 {
+    ($($($($i:ident)*)?)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo6 {
+    ($($($($i:ident)?)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo7 {
+    ($($($($i:ident)?)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo8 {
+    ($($($($i:ident)*)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo9 {
+    ($($($($i:ident)?)*)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo10 {
+    ($($($($i:ident)?)*)+) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo11 {
+    ($($($($i:ident)+)?)*) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo12 {
+    ($($($($i:ident)+)*)?) => {};
+    //~^ ERROR repetition matches empty token tree
+}
+
+fn main() {
+    foo1!();
+    foo2!();
+    foo3!();
+    foo4!();
+    foo5!();
+    foo6!();
+    foo7!();
+    foo8!();
+    foo9!();
+    foo10!();
+    foo11!();
+    foo12!();
+}
diff --git a/tests/ui/macros/issue-57597.stderr b/tests/ui/macros/issue-57597.stderr
new file mode 100644
index 00000000000..0a02ac8c499
--- /dev/null
+++ b/tests/ui/macros/issue-57597.stderr
@@ -0,0 +1,74 @@
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:8:7
+   |
+LL |     ($($($i:ident)?)+) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:13:7
+   |
+LL |     ($($($i:ident)?)*) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:18:7
+   |
+LL |     ($($($i:ident)?)?) => {};
+   |       ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:23:7
+   |
+LL |     ($($($($i:ident)?)?)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:28:7
+   |
+LL |     ($($($($i:ident)*)?)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:33:7
+   |
+LL |     ($($($($i:ident)?)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:38:7
+   |
+LL |     ($($($($i:ident)?)?)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:43:7
+   |
+LL |     ($($($($i:ident)*)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:48:7
+   |
+LL |     ($($($($i:ident)?)*)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:53:7
+   |
+LL |     ($($($($i:ident)?)*)+) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:58:7
+   |
+LL |     ($($($($i:ident)+)?)*) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+  --> $DIR/issue-57597.rs:63:7
+   |
+LL |     ($($($($i:ident)+)*)?) => {};
+   |       ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/macros/issue-58490.rs b/tests/ui/macros/issue-58490.rs
new file mode 100644
index 00000000000..97e71c9a1ce
--- /dev/null
+++ b/tests/ui/macros/issue-58490.rs
@@ -0,0 +1,26 @@
+// Regression test for #58490
+
+macro_rules! a {
+    ( @1 $i:item ) => {
+        a! { @2 $i }
+    };
+    ( @2 $i:item ) => {
+        $i
+    };
+}
+mod b {
+    a! {
+        @1
+        #[macro_export]
+        macro_rules! b { () => () }
+    }
+    #[macro_export]
+    macro_rules! b { () => () }
+    //~^ ERROR: the name `b` is defined multiple times
+}
+mod c {
+    #[allow(unused_imports)]
+    use crate::b;
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-58490.stderr b/tests/ui/macros/issue-58490.stderr
new file mode 100644
index 00000000000..b1f0896f3b6
--- /dev/null
+++ b/tests/ui/macros/issue-58490.stderr
@@ -0,0 +1,14 @@
+error[E0428]: the name `b` is defined multiple times
+  --> $DIR/issue-58490.rs:18:5
+   |
+LL |         macro_rules! b { () => () }
+   |         -------------- previous definition of the macro `b` here
+...
+LL |     macro_rules! b { () => () }
+   |     ^^^^^^^^^^^^^^ `b` redefined here
+   |
+   = note: `b` must be defined only once in the macro namespace of this module
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
diff --git a/tests/ui/macros/issue-61033-1.rs b/tests/ui/macros/issue-61033-1.rs
new file mode 100644
index 00000000000..18df3f6ee94
--- /dev/null
+++ b/tests/ui/macros/issue-61033-1.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #61033.
+
+macro_rules! test1 {
+    ($x:ident, $($tt:tt)*) => { $($tt)+ } //~ ERROR this must repeat at least once
+}
+
+fn main() {
+    test1!(x,);
+    let _recovery_witness: () = 0; //~ ERROR mismatched types
+}
diff --git a/tests/ui/macros/issue-61033-1.stderr b/tests/ui/macros/issue-61033-1.stderr
new file mode 100644
index 00000000000..18205c3436b
--- /dev/null
+++ b/tests/ui/macros/issue-61033-1.stderr
@@ -0,0 +1,17 @@
+error: this must repeat at least once
+  --> $DIR/issue-61033-1.rs:4:34
+   |
+LL |     ($x:ident, $($tt:tt)*) => { $($tt)+ }
+   |                                  ^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/issue-61033-1.rs:9:33
+   |
+LL |     let _recovery_witness: () = 0;
+   |                            --   ^ expected `()`, found integer
+   |                            |
+   |                            expected due to this
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/macros/issue-61033-2.rs b/tests/ui/macros/issue-61033-2.rs
new file mode 100644
index 00000000000..1760ba1584d
--- /dev/null
+++ b/tests/ui/macros/issue-61033-2.rs
@@ -0,0 +1,25 @@
+// Regression test for issue #61033.
+
+macro_rules! test2 {
+    (
+        $(* $id1:ident)*
+        $(+ $id2:ident)*
+    ) => {
+        $(
+        //~^ ERROR meta-variable `id1` repeats 2 times
+        //~| ERROR meta-variable `id1` repeats 2 times
+            $id1 + $id2 // $id1 and $id2 may repeat different numbers of times
+        )*
+    }
+}
+
+fn main() {
+    test2! {
+        * a * b
+        + a + b + c
+    }
+    test2! {
+        * a * b
+        + a + b + c + d
+    }
+}
diff --git a/tests/ui/macros/issue-61033-2.stderr b/tests/ui/macros/issue-61033-2.stderr
new file mode 100644
index 00000000000..cdfe7934a0c
--- /dev/null
+++ b/tests/ui/macros/issue-61033-2.stderr
@@ -0,0 +1,24 @@
+error: meta-variable `id1` repeats 2 times, but `id2` repeats 3 times
+  --> $DIR/issue-61033-2.rs:8:10
+   |
+LL |           $(
+   |  __________^
+LL | |
+LL | |
+LL | |             $id1 + $id2 // $id1 and $id2 may repeat different numbers of times
+LL | |         )*
+   | |_________^
+
+error: meta-variable `id1` repeats 2 times, but `id2` repeats 4 times
+  --> $DIR/issue-61033-2.rs:8:10
+   |
+LL |           $(
+   |  __________^
+LL | |
+LL | |
+LL | |             $id1 + $id2 // $id1 and $id2 may repeat different numbers of times
+LL | |         )*
+   | |_________^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-61053-different-kleene.rs b/tests/ui/macros/issue-61053-different-kleene.rs
new file mode 100644
index 00000000000..9b7babdbb70
--- /dev/null
+++ b/tests/ui/macros/issue-61053-different-kleene.rs
@@ -0,0 +1,30 @@
+#![deny(meta_variable_misuse)]
+
+macro_rules! foo {
+    () => {};
+    ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
+    //~^ ERROR meta-variable repeats with
+    ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; //~ERROR meta-variable repeats with
+}
+
+macro_rules! bar {
+    () => {};
+    (test) => {
+        macro_rules! nested {
+            () => {};
+            ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
+            //~^ ERROR meta-variable repeats with
+            ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ }; //~ERROR meta-variable repeats with
+        }
+    };
+    ( $( $i:ident = $($j:ident),+ );* ) => {
+        $(macro_rules! $i {
+            () => { 0 $( + $j )* }; //~ ERROR meta-variable repeats with
+        })*
+    };
+}
+
+fn main() {
+    foo!();
+    bar!();
+}
diff --git a/tests/ui/macros/issue-61053-different-kleene.stderr b/tests/ui/macros/issue-61053-different-kleene.stderr
new file mode 100644
index 00000000000..aa8bac13b61
--- /dev/null
+++ b/tests/ui/macros/issue-61053-different-kleene.stderr
@@ -0,0 +1,45 @@
+error: meta-variable repeats with different Kleene operator
+  --> $DIR/issue-61053-different-kleene.rs:5:57
+   |
+LL |     ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
+   |                                 - expected repetition   ^^   - conflicting repetition
+   |
+note: the lint level is defined here
+  --> $DIR/issue-61053-different-kleene.rs:1:9
+   |
+LL | #![deny(meta_variable_misuse)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: meta-variable repeats with different Kleene operator
+  --> $DIR/issue-61053-different-kleene.rs:7:41
+   |
+LL |     ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ };
+   |                          -              ^^      - conflicting repetition
+   |                          |
+   |                          expected repetition
+
+error: meta-variable repeats with different Kleene operator
+  --> $DIR/issue-61053-different-kleene.rs:15:65
+   |
+LL |             ( $( $i:ident = $($j:ident),+ );* ) => { $( $( $i = $j; )* )* };
+   |                                         - expected repetition   ^^   - conflicting repetition
+
+error: meta-variable repeats with different Kleene operator
+  --> $DIR/issue-61053-different-kleene.rs:17:49
+   |
+LL |             ( $( $($j:ident),+ );* ) => { $( $( $j; )+ )+ };
+   |                                  -              ^^      - conflicting repetition
+   |                                  |
+   |                                  expected repetition
+
+error: meta-variable repeats with different Kleene operator
+  --> $DIR/issue-61053-different-kleene.rs:22:28
+   |
+LL |     ( $( $i:ident = $($j:ident),+ );* ) => {
+   |                                 - expected repetition
+LL |         $(macro_rules! $i {
+LL |             () => { 0 $( + $j )* };
+   |                            ^^  - conflicting repetition
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/macros/issue-61053-duplicate-binder.rs b/tests/ui/macros/issue-61053-duplicate-binder.rs
new file mode 100644
index 00000000000..34aa571c11e
--- /dev/null
+++ b/tests/ui/macros/issue-61053-duplicate-binder.rs
@@ -0,0 +1,14 @@
+#![deny(meta_variable_misuse)]
+
+macro_rules! foo {
+    () => {};
+    (error) => {
+        macro_rules! bar {
+            ($x:tt $x:tt) => { $x }; //~ ERROR duplicate matcher binding
+        }
+    };
+}
+
+fn main() {
+    foo!();
+}
diff --git a/tests/ui/macros/issue-61053-duplicate-binder.stderr b/tests/ui/macros/issue-61053-duplicate-binder.stderr
new file mode 100644
index 00000000000..5a2af45d077
--- /dev/null
+++ b/tests/ui/macros/issue-61053-duplicate-binder.stderr
@@ -0,0 +1,16 @@
+error: duplicate matcher binding
+  --> $DIR/issue-61053-duplicate-binder.rs:7:20
+   |
+LL |             ($x:tt $x:tt) => { $x };
+   |              --    ^^
+   |              |
+   |              previous declaration
+   |
+note: the lint level is defined here
+  --> $DIR/issue-61053-duplicate-binder.rs:1:9
+   |
+LL | #![deny(meta_variable_misuse)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-61053-missing-repetition.rs b/tests/ui/macros/issue-61053-missing-repetition.rs
new file mode 100644
index 00000000000..6b36c730b82
--- /dev/null
+++ b/tests/ui/macros/issue-61053-missing-repetition.rs
@@ -0,0 +1,28 @@
+#![deny(meta_variable_misuse)]
+
+macro_rules! foo {
+    () => {};
+    ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* };
+    //~^ ERROR variable 'j' is still repeating
+}
+
+macro_rules! bar {
+    () => {};
+    (test) => {
+        macro_rules! nested {
+            () => {};
+            ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* };
+            //~^ ERROR variable 'j' is still repeating
+        }
+    };
+    ( $( $i:ident = $($j:ident),+ );* ) => {
+        $(macro_rules! $i {
+            () => { $j }; //~ ERROR variable 'j' is still repeating
+        })*
+    };
+}
+
+fn main() {
+    foo!();
+    bar!();
+}
diff --git a/tests/ui/macros/issue-61053-missing-repetition.stderr b/tests/ui/macros/issue-61053-missing-repetition.stderr
new file mode 100644
index 00000000000..738f711f04e
--- /dev/null
+++ b/tests/ui/macros/issue-61053-missing-repetition.stderr
@@ -0,0 +1,33 @@
+error: variable 'j' is still repeating at this depth
+  --> $DIR/issue-61053-missing-repetition.rs:5:52
+   |
+LL |     ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* };
+   |                                -                   ^^
+   |                                |
+   |                                expected repetition
+   |
+note: the lint level is defined here
+  --> $DIR/issue-61053-missing-repetition.rs:1:9
+   |
+LL | #![deny(meta_variable_misuse)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: variable 'j' is still repeating at this depth
+  --> $DIR/issue-61053-missing-repetition.rs:14:60
+   |
+LL |             ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* };
+   |                                        -                   ^^
+   |                                        |
+   |                                        expected repetition
+
+error: variable 'j' is still repeating at this depth
+  --> $DIR/issue-61053-missing-repetition.rs:20:21
+   |
+LL |     ( $( $i:ident = $($j:ident),+ );* ) => {
+   |                                 - expected repetition
+LL |         $(macro_rules! $i {
+LL |             () => { $j };
+   |                     ^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/issue-61053-unbound.rs b/tests/ui/macros/issue-61053-unbound.rs
new file mode 100644
index 00000000000..b75cdce0cf4
--- /dev/null
+++ b/tests/ui/macros/issue-61053-unbound.rs
@@ -0,0 +1,28 @@
+#![deny(meta_variable_misuse)]
+
+macro_rules! foo {
+    () => {};
+    ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+    //~^ ERROR unknown macro variable
+}
+
+macro_rules! bar {
+    () => {};
+    (test) => {
+        macro_rules! nested {
+            () => {};
+            ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+            //~^ ERROR unknown macro variable
+        }
+    };
+    ( $( $i:ident = $($j:ident),+ );* ) => {
+        $(macro_rules! $i {
+            () => { $( $i = $k)+ }; //~ ERROR unknown macro variable
+        })*
+    };
+}
+
+fn main() {
+    foo!();
+    bar!();
+}
diff --git a/tests/ui/macros/issue-61053-unbound.stderr b/tests/ui/macros/issue-61053-unbound.stderr
new file mode 100644
index 00000000000..0d64effc967
--- /dev/null
+++ b/tests/ui/macros/issue-61053-unbound.stderr
@@ -0,0 +1,26 @@
+error: unknown macro variable `k`
+  --> $DIR/issue-61053-unbound.rs:5:55
+   |
+LL |     ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+   |                                                       ^^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-61053-unbound.rs:1:9
+   |
+LL | #![deny(meta_variable_misuse)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unknown macro variable `k`
+  --> $DIR/issue-61053-unbound.rs:14:63
+   |
+LL |             ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+   |                                                               ^^
+
+error: unknown macro variable `k`
+  --> $DIR/issue-61053-unbound.rs:20:29
+   |
+LL |             () => { $( $i = $k)+ };
+   |                             ^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/issue-63102.rs b/tests/ui/macros/issue-63102.rs
new file mode 100644
index 00000000000..6af5b186806
--- /dev/null
+++ b/tests/ui/macros/issue-63102.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+#![feature(decl_macro)]
+macro foo {
+    () => {},
+}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-6596-1.rs b/tests/ui/macros/issue-6596-1.rs
new file mode 100644
index 00000000000..25f1d650072
--- /dev/null
+++ b/tests/ui/macros/issue-6596-1.rs
@@ -0,0 +1,10 @@
+macro_rules! e {
+    ($inp:ident) => (
+        $nonexistent
+        //~^ ERROR expected expression, found `$`
+    );
+}
+
+fn main() {
+    e!(foo);
+}
diff --git a/tests/ui/macros/issue-6596-1.stderr b/tests/ui/macros/issue-6596-1.stderr
new file mode 100644
index 00000000000..7ab3685c5cb
--- /dev/null
+++ b/tests/ui/macros/issue-6596-1.stderr
@@ -0,0 +1,13 @@
+error: expected expression, found `$`
+  --> $DIR/issue-6596-1.rs:3:9
+   |
+LL |         $nonexistent
+   |         ^^^^^^^^^^^^ expected expression
+...
+LL |     e!(foo);
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-68058.rs b/tests/ui/macros/issue-68058.rs
new file mode 100644
index 00000000000..24da2620c2e
--- /dev/null
+++ b/tests/ui/macros/issue-68058.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+macro_rules! foo {
+    ($doc: expr) => {
+        fn f() {
+            #[doc = $doc]
+            ()
+        }
+    };
+}
+
+foo!("doc");
+
+fn main() {}
diff --git a/tests/ui/macros/issue-68060.rs b/tests/ui/macros/issue-68060.rs
new file mode 100644
index 00000000000..fb40cd5387b
--- /dev/null
+++ b/tests/ui/macros/issue-68060.rs
@@ -0,0 +1,15 @@
+fn main() {
+    (0..)
+        .map(
+            #[target_feature(enable = "")]
+            //~^ ERROR: attribute should be applied to a function
+            //~| ERROR: feature named `` is not valid
+            //~| NOTE: `` is not valid for this target
+            #[track_caller]
+            //~^ ERROR: `#[track_caller]` on closures is currently unstable
+            //~| NOTE: see issue #87417
+            |_| (),
+            //~^ NOTE: not a function
+        )
+        .next();
+}
diff --git a/tests/ui/macros/issue-68060.stderr b/tests/ui/macros/issue-68060.stderr
new file mode 100644
index 00000000000..52e6ed92e9d
--- /dev/null
+++ b/tests/ui/macros/issue-68060.stderr
@@ -0,0 +1,27 @@
+error: attribute should be applied to a function definition
+  --> $DIR/issue-68060.rs:4:13
+   |
+LL |             #[target_feature(enable = "")]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |             |_| (),
+   |             ------ not a function definition
+
+error: the feature named `` is not valid for this target
+  --> $DIR/issue-68060.rs:4:30
+   |
+LL |             #[target_feature(enable = "")]
+   |                              ^^^^^^^^^^^ `` is not valid for this target
+
+error[E0658]: `#[track_caller]` on closures is currently unstable
+  --> $DIR/issue-68060.rs:8:13
+   |
+LL |             #[track_caller]
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
+   = help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/issue-69838-dir/bar.rs b/tests/ui/macros/issue-69838-dir/bar.rs
new file mode 100644
index 00000000000..ec12f8c5cb4
--- /dev/null
+++ b/tests/ui/macros/issue-69838-dir/bar.rs
@@ -0,0 +1,3 @@
+// ignore-test -- this is an auxiliary file as part of another test.
+
+pub fn i_am_in_bar() {}
diff --git a/tests/ui/macros/issue-69838-dir/included.rs b/tests/ui/macros/issue-69838-dir/included.rs
new file mode 100644
index 00000000000..9900b8fd509
--- /dev/null
+++ b/tests/ui/macros/issue-69838-dir/included.rs
@@ -0,0 +1,3 @@
+// ignore-test -- this is an auxiliary file as part of another test.
+
+pub mod bar;
diff --git a/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs b/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs
new file mode 100644
index 00000000000..2a4e97f0ef5
--- /dev/null
+++ b/tests/ui/macros/issue-69838-mods-relative-to-included-path.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+include!("issue-69838-dir/included.rs");
+
+fn main() {
+    bar::i_am_in_bar();
+}
diff --git a/tests/ui/macros/issue-70446.rs b/tests/ui/macros/issue-70446.rs
new file mode 100644
index 00000000000..407094d55ff
--- /dev/null
+++ b/tests/ui/macros/issue-70446.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+macro_rules! foo {
+    ($(: $p:path)? $(: $l:lifetime)? ) => { bar! {$(: $p)? $(: $l)? } };
+}
+
+macro_rules! bar {
+    ($(: $p:path)? $(: $l:lifetime)? ) => {};
+}
+
+foo! {: 'a }
+
+fn main() {}
diff --git a/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs b/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs
new file mode 100644
index 00000000000..e76b09d4bb9
--- /dev/null
+++ b/tests/ui/macros/issue-75982-foreign-macro-weird-mod.rs
@@ -0,0 +1,13 @@
+// aux-build:issue-75982.rs
+// check-pass
+
+// Regression test for issue #75982
+// Tests that don't ICE when invoking a foreign macro
+// that occurs inside a module with a weird parent.
+
+extern crate issue_75982;
+
+fn main() {
+    issue_75982::first_macro!();
+    issue_75982::second_macro!();
+}
diff --git a/tests/ui/macros/issue-77475.rs b/tests/ui/macros/issue-77475.rs
new file mode 100644
index 00000000000..7b32a33ea4f
--- /dev/null
+++ b/tests/ui/macros/issue-77475.rs
@@ -0,0 +1,10 @@
+// check-pass
+// Regression test of #77475, this used to be ICE.
+
+#![feature(decl_macro)]
+
+use crate as _;
+
+pub macro ice(){}
+
+fn main() {}
diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.rs b/tests/ui/macros/issue-78325-inconsistent-resolution.rs
new file mode 100644
index 00000000000..919eca4f9bf
--- /dev/null
+++ b/tests/ui/macros/issue-78325-inconsistent-resolution.rs
@@ -0,0 +1,12 @@
+macro_rules! define_other_core {
+    ( ) => {
+        extern crate std as core;
+        //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+    };
+}
+
+fn main() {
+    core::panic!();
+}
+
+define_other_core!();
diff --git a/tests/ui/macros/issue-78325-inconsistent-resolution.stderr b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr
new file mode 100644
index 00000000000..53a0a0793b2
--- /dev/null
+++ b/tests/ui/macros/issue-78325-inconsistent-resolution.stderr
@@ -0,0 +1,13 @@
+error: macro-expanded `extern crate` items cannot shadow names passed with `--extern`
+  --> $DIR/issue-78325-inconsistent-resolution.rs:3:9
+   |
+LL |         extern crate std as core;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | define_other_core!();
+   | -------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-78333.rs b/tests/ui/macros/issue-78333.rs
new file mode 100644
index 00000000000..c376f206704
--- /dev/null
+++ b/tests/ui/macros/issue-78333.rs
@@ -0,0 +1,13 @@
+// build-pass
+
+#![no_implicit_prelude]
+
+fn main() {
+    ::std::panic!();
+    ::std::todo!();
+    ::std::unimplemented!();
+    ::std::assert_eq!(0, 0);
+    ::std::assert_ne!(0, 1);
+    ::std::dbg!(123);
+    ::std::unreachable!();
+}
diff --git a/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs b/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs
new file mode 100644
index 00000000000..9d1fae7a234
--- /dev/null
+++ b/tests/ui/macros/issue-78892-substitution-in-statement-attr.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// regression test for #78892
+
+macro_rules! mac {
+    ($lint_name:ident) => {{
+        #[allow($lint_name)]
+        let _ = ();
+    }};
+}
+
+fn main() {
+    mac!(dead_code)
+}
diff --git a/tests/ui/macros/issue-81006.rs b/tests/ui/macros/issue-81006.rs
new file mode 100644
index 00000000000..602eb597428
--- /dev/null
+++ b/tests/ui/macros/issue-81006.rs
@@ -0,0 +1,10 @@
+// check-fail
+
+// First format below would cause a panic, second would generate error with incorrect span
+
+fn main() {
+    let _ = format!("→{}→\n");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
+    let _ = format!("→{} \n");
+    //~^ ERROR 1 positional argument in format string, but no arguments were given
+}
diff --git a/tests/ui/macros/issue-81006.stderr b/tests/ui/macros/issue-81006.stderr
new file mode 100644
index 00000000000..14a8cbe0155
--- /dev/null
+++ b/tests/ui/macros/issue-81006.stderr
@@ -0,0 +1,14 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-81006.rs:6:23
+   |
+LL |     let _ = format!("→{}→\n");
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-81006.rs:8:23
+   |
+LL |     let _ = format!("→{} \n");
+   |                       ^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-83340.rs b/tests/ui/macros/issue-83340.rs
new file mode 100644
index 00000000000..d26200295cd
--- /dev/null
+++ b/tests/ui/macros/issue-83340.rs
@@ -0,0 +1,8 @@
+// check-fail
+
+fn main() {
+    println!(
+        "\
+\n {} │", //~ ERROR: 1 positional argument in format string, but no arguments were given
+    );
+}
diff --git a/tests/ui/macros/issue-83340.stderr b/tests/ui/macros/issue-83340.stderr
new file mode 100644
index 00000000000..1935de02b57
--- /dev/null
+++ b/tests/ui/macros/issue-83340.stderr
@@ -0,0 +1,8 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-83340.rs:6:4
+   |
+LL | \n {} │",
+   |    ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-83344.rs b/tests/ui/macros/issue-83344.rs
new file mode 100644
index 00000000000..c5f7f723587
--- /dev/null
+++ b/tests/ui/macros/issue-83344.rs
@@ -0,0 +1,6 @@
+// check-fail
+
+fn main() {
+    println!("{}\
+"); //~^ ERROR: 1 positional argument in format string, but no arguments were given
+}
diff --git a/tests/ui/macros/issue-83344.stderr b/tests/ui/macros/issue-83344.stderr
new file mode 100644
index 00000000000..1ef70f87a1f
--- /dev/null
+++ b/tests/ui/macros/issue-83344.stderr
@@ -0,0 +1,8 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/issue-83344.rs:4:15
+   |
+LL |     println!("{}\
+   |               ^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-84195-lint-anon-const.rs b/tests/ui/macros/issue-84195-lint-anon-const.rs
new file mode 100644
index 00000000000..71c76832015
--- /dev/null
+++ b/tests/ui/macros/issue-84195-lint-anon-const.rs
@@ -0,0 +1,14 @@
+// Regression test for issue #84195
+// Checks that we properly fire lints that occur inside
+// anon consts.
+
+#![deny(semicolon_in_expressions_from_macros)]
+
+macro_rules! len {
+    () => { 0; }; //~  ERROR trailing semicolon
+                  //~| WARN this was previously accepted
+}
+
+fn main() {
+    let val: [u8; len!()] = [];
+}
diff --git a/tests/ui/macros/issue-84195-lint-anon-const.stderr b/tests/ui/macros/issue-84195-lint-anon-const.stderr
new file mode 100644
index 00000000000..306c08b1357
--- /dev/null
+++ b/tests/ui/macros/issue-84195-lint-anon-const.stderr
@@ -0,0 +1,20 @@
+error: trailing semicolon in macro used in expression position
+  --> $DIR/issue-84195-lint-anon-const.rs:8:14
+   |
+LL |     () => { 0; };
+   |              ^
+...
+LL |     let val: [u8; len!()] = [];
+   |                   ------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+note: the lint level is defined here
+  --> $DIR/issue-84195-lint-anon-const.rs:5:9
+   |
+LL | #![deny(semicolon_in_expressions_from_macros)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `len` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-84429-matches-edition.rs b/tests/ui/macros/issue-84429-matches-edition.rs
new file mode 100644
index 00000000000..53f134c265f
--- /dev/null
+++ b/tests/ui/macros/issue-84429-matches-edition.rs
@@ -0,0 +1,9 @@
+// edition:2021
+// check-pass
+//
+// Regression test for issue #84429
+// Tests that we can properly invoke `matches!` from a 2021-edition crate.
+
+fn main() {
+    let _b = matches!(b'3', b'0' ..= b'9');
+}
diff --git a/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs
new file mode 100644
index 00000000000..7a1e62d49d3
--- /dev/null
+++ b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.rs
@@ -0,0 +1,16 @@
+// Regression test for #84632: Recursion limit is ignored
+// for builtin macros that eagerly expands.
+
+#![recursion_limit = "15"]
+macro_rules! a {
+    () => ("");
+    (A) => (concat!("", a!()));
+    (A, $($A:ident),*) => (concat!("", a!($($A),*)))
+    //~^ ERROR recursion limit reached
+    //~| HELP consider increasing the recursion limit
+}
+
+fn main() {
+    a!(A, A, A, A, A);
+    a!(A, A, A, A, A, A, A, A, A, A, A);
+}
diff --git a/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr
new file mode 100644
index 00000000000..e266617bd22
--- /dev/null
+++ b/tests/ui/macros/issue-84632-eager-expansion-recursion-limit.stderr
@@ -0,0 +1,14 @@
+error: recursion limit reached while expanding `concat!`
+  --> $DIR/issue-84632-eager-expansion-recursion-limit.rs:8:28
+   |
+LL |     (A, $($A:ident),*) => (concat!("", a!($($A),*)))
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     a!(A, A, A, A, A, A, A, A, A, A, A);
+   |     ----------------------------------- in this macro invocation
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "30"]` attribute to your crate (`issue_84632_eager_expansion_recursion_limit`)
+   = note: this error originates in the macro `a` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-86082-option-env-invalid-char.rs b/tests/ui/macros/issue-86082-option-env-invalid-char.rs
new file mode 100644
index 00000000000..b556b24d6aa
--- /dev/null
+++ b/tests/ui/macros/issue-86082-option-env-invalid-char.rs
@@ -0,0 +1,10 @@
+// check-pass
+//
+// Regression test for issue #86082
+//
+// Checks that option_env! does not panic on receiving an invalid
+// environment variable name.
+
+fn main() {
+    option_env!("\0=");
+}
diff --git a/tests/ui/macros/issue-86865.rs b/tests/ui/macros/issue-86865.rs
new file mode 100644
index 00000000000..01e0a20a511
--- /dev/null
+++ b/tests/ui/macros/issue-86865.rs
@@ -0,0 +1,11 @@
+use std::fmt::Write;
+
+fn main() {
+    println!(b"foo");
+    //~^ ERROR format argument must be a string literal
+    //~| HELP consider removing the leading `b`
+    let mut s = String::new();
+    write!(s, b"foo{}", "bar");
+    //~^ ERROR format argument must be a string literal
+    //~| HELP consider removing the leading `b`
+}
diff --git a/tests/ui/macros/issue-86865.stderr b/tests/ui/macros/issue-86865.stderr
new file mode 100644
index 00000000000..eed75536631
--- /dev/null
+++ b/tests/ui/macros/issue-86865.stderr
@@ -0,0 +1,18 @@
+error: format argument must be a string literal
+  --> $DIR/issue-86865.rs:4:14
+   |
+LL |     println!(b"foo");
+   |              -^^^^^
+   |              |
+   |              help: consider removing the leading `b`
+
+error: format argument must be a string literal
+  --> $DIR/issue-86865.rs:8:15
+   |
+LL |     write!(s, b"foo{}", "bar");
+   |               -^^^^^^^
+   |               |
+   |               help: consider removing the leading `b`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/issue-8709.rs b/tests/ui/macros/issue-8709.rs
new file mode 100644
index 00000000000..ea7525d4477
--- /dev/null
+++ b/tests/ui/macros/issue-8709.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+macro_rules! sty {
+    ($t:ty) => (stringify!($t))
+}
+
+macro_rules! spath {
+    ($t:path) => (stringify!($t))
+}
+
+fn main() {
+    assert_eq!(sty!(isize), "isize");
+    assert_eq!(spath!(std::option), "std::option");
+}
diff --git a/tests/ui/macros/issue-87877.rs b/tests/ui/macros/issue-87877.rs
new file mode 100644
index 00000000000..a40e2c5f970
--- /dev/null
+++ b/tests/ui/macros/issue-87877.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+macro_rules! two_items {
+    () => {
+        extern "C" {}
+        extern "C" {}
+    };
+}
+
+macro_rules! single_expr_funneler {
+    ($expr:expr) => {
+        $expr; // note the semicolon, it changes the statement kind during parsing
+    };
+}
+
+macro_rules! single_item_funneler {
+    ($item:item) => {
+        $item
+    };
+}
+
+fn main() {
+    single_expr_funneler! { two_items! {} }
+    single_item_funneler! { two_items! {} }
+}
diff --git a/tests/ui/macros/issue-88206.rs b/tests/ui/macros/issue-88206.rs
new file mode 100644
index 00000000000..14e2f66068b
--- /dev/null
+++ b/tests/ui/macros/issue-88206.rs
@@ -0,0 +1,66 @@
+// compile-flags: -Z deduplicate-diagnostics=yes
+
+#![warn(unused_imports)]
+
+use std::str::*;
+//~^ NOTE `from_utf8` is imported here, but it is a function
+//~| NOTE `from_utf8_mut` is imported here, but it is a function
+//~| NOTE `from_utf8_unchecked` is imported here, but it is a function
+
+mod hey {
+    pub trait Serialize {}
+    pub trait Deserialize {}
+
+    pub struct X(i32);
+}
+
+use hey::{Serialize, Deserialize, X};
+//~^ NOTE `Serialize` is imported here, but it is only a trait, without a derive macro
+//~| NOTE `Deserialize` is imported here, but it is a trait
+//~| NOTE `X` is imported here, but it is a struct
+
+#[derive(Serialize)]
+//~^ ERROR cannot find derive macro `Serialize`
+struct A;
+
+#[derive(from_utf8_mut)]
+//~^ ERROR cannot find derive macro `from_utf8_mut`
+struct B;
+
+#[derive(println)]
+//~^ ERROR cannot find derive macro `println`
+//~| NOTE `println` is in scope, but it is a function-like macro
+struct C;
+
+#[Deserialize]
+//~^ ERROR cannot find attribute `Deserialize`
+struct D;
+
+#[from_utf8_unchecked]
+//~^ ERROR cannot find attribute `from_utf8_unchecked`
+struct E;
+
+#[println]
+//~^ ERROR cannot find attribute `println`
+//~| NOTE `println` is in scope, but it is a function-like macro
+struct F;
+
+fn main() {
+    from_utf8!();
+    //~^ ERROR cannot find macro `from_utf8`
+
+    Box!();
+    //~^ ERROR cannot find macro `Box`
+    //~| NOTE `Box` is in scope, but it is a struct
+
+    Copy!();
+    //~^ ERROR cannot find macro `Copy`
+    //~| NOTE `Copy` is in scope, but it is a derive macro
+
+    test!();
+    //~^ ERROR cannot find macro `test`
+    //~| NOTE `test` is in scope, but it is an attribute
+
+    X!();
+    //~^ ERROR cannot find macro `X`
+}
diff --git a/tests/ui/macros/issue-88206.stderr b/tests/ui/macros/issue-88206.stderr
new file mode 100644
index 00000000000..f7f5b564880
--- /dev/null
+++ b/tests/ui/macros/issue-88206.stderr
@@ -0,0 +1,114 @@
+error: cannot find macro `X` in this scope
+  --> $DIR/issue-88206.rs:64:5
+   |
+LL |     X!();
+   |     ^
+   |
+note: `X` is imported here, but it is a struct, not a macro
+  --> $DIR/issue-88206.rs:17:35
+   |
+LL | use hey::{Serialize, Deserialize, X};
+   |                                   ^
+
+error: cannot find macro `test` in this scope
+  --> $DIR/issue-88206.rs:60:5
+   |
+LL |     test!();
+   |     ^^^^
+   |
+   = note: `test` is in scope, but it is an attribute: `#[test]`
+
+error: cannot find macro `Copy` in this scope
+  --> $DIR/issue-88206.rs:56:5
+   |
+LL |     Copy!();
+   |     ^^^^
+   |
+   = note: `Copy` is in scope, but it is a derive macro: `#[derive(Copy)]`
+
+error: cannot find macro `Box` in this scope
+  --> $DIR/issue-88206.rs:52:5
+   |
+LL |     Box!();
+   |     ^^^
+   |
+   = note: `Box` is in scope, but it is a struct, not a macro
+
+error: cannot find macro `from_utf8` in this scope
+  --> $DIR/issue-88206.rs:49:5
+   |
+LL |     from_utf8!();
+   |     ^^^^^^^^^
+   |
+note: `from_utf8` is imported here, but it is a function, not a macro
+  --> $DIR/issue-88206.rs:5:5
+   |
+LL | use std::str::*;
+   |     ^^^^^^^^^^^
+
+error: cannot find attribute `println` in this scope
+  --> $DIR/issue-88206.rs:43:3
+   |
+LL | #[println]
+   |   ^^^^^^^
+   |
+   = note: `println` is in scope, but it is a function-like macro
+
+error: cannot find attribute `from_utf8_unchecked` in this scope
+  --> $DIR/issue-88206.rs:39:3
+   |
+LL | #[from_utf8_unchecked]
+   |   ^^^^^^^^^^^^^^^^^^^
+   |
+note: `from_utf8_unchecked` is imported here, but it is a function, not an attribute
+  --> $DIR/issue-88206.rs:5:5
+   |
+LL | use std::str::*;
+   |     ^^^^^^^^^^^
+
+error: cannot find attribute `Deserialize` in this scope
+  --> $DIR/issue-88206.rs:35:3
+   |
+LL | #[Deserialize]
+   |   ^^^^^^^^^^^
+   |
+note: `Deserialize` is imported here, but it is a trait, not an attribute
+  --> $DIR/issue-88206.rs:17:22
+   |
+LL | use hey::{Serialize, Deserialize, X};
+   |                      ^^^^^^^^^^^
+
+error: cannot find derive macro `println` in this scope
+  --> $DIR/issue-88206.rs:30:10
+   |
+LL | #[derive(println)]
+   |          ^^^^^^^
+   |
+   = note: `println` is in scope, but it is a function-like macro
+
+error: cannot find derive macro `from_utf8_mut` in this scope
+  --> $DIR/issue-88206.rs:26:10
+   |
+LL | #[derive(from_utf8_mut)]
+   |          ^^^^^^^^^^^^^
+   |
+note: `from_utf8_mut` is imported here, but it is a function, not a derive macro
+  --> $DIR/issue-88206.rs:5:5
+   |
+LL | use std::str::*;
+   |     ^^^^^^^^^^^
+
+error: cannot find derive macro `Serialize` in this scope
+  --> $DIR/issue-88206.rs:22:10
+   |
+LL | #[derive(Serialize)]
+   |          ^^^^^^^^^
+   |
+note: `Serialize` is imported here, but it is only a trait, without a derive macro
+  --> $DIR/issue-88206.rs:17:11
+   |
+LL | use hey::{Serialize, Deserialize, X};
+   |           ^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/macros/issue-88228.rs b/tests/ui/macros/issue-88228.rs
new file mode 100644
index 00000000000..cbdef5f0d40
--- /dev/null
+++ b/tests/ui/macros/issue-88228.rs
@@ -0,0 +1,23 @@
+// compile-flags: -Z deduplicate-diagnostics=yes
+// edition:2018
+
+mod hey {
+    pub use Copy as Bla;
+    pub use std::println as bla;
+}
+
+#[derive(Bla)]
+//~^ ERROR cannot find derive macro `Bla`
+//~| NOTE consider importing this derive macro
+struct A;
+
+#[derive(println)]
+//~^ ERROR cannot find derive macro `println`
+//~|`println` is in scope, but it is a function-like macro
+struct B;
+
+fn main() {
+    bla!();
+    //~^ ERROR cannot find macro `bla`
+    //~| NOTE consider importing this macro
+}
diff --git a/tests/ui/macros/issue-88228.stderr b/tests/ui/macros/issue-88228.stderr
new file mode 100644
index 00000000000..62afa67a783
--- /dev/null
+++ b/tests/ui/macros/issue-88228.stderr
@@ -0,0 +1,28 @@
+error: cannot find macro `bla` in this scope
+  --> $DIR/issue-88228.rs:20:5
+   |
+LL |     bla!();
+   |     ^^^
+   |
+   = note: consider importing this macro:
+           crate::hey::bla
+
+error: cannot find derive macro `println` in this scope
+  --> $DIR/issue-88228.rs:14:10
+   |
+LL | #[derive(println)]
+   |          ^^^^^^^
+   |
+   = note: `println` is in scope, but it is a function-like macro
+
+error: cannot find derive macro `Bla` in this scope
+  --> $DIR/issue-88228.rs:9:10
+   |
+LL | #[derive(Bla)]
+   |          ^^^
+   |
+   = note: consider importing this derive macro:
+           crate::hey::Bla
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/issue-8851.rs b/tests/ui/macros/issue-8851.rs
new file mode 100644
index 00000000000..faacfe5f895
--- /dev/null
+++ b/tests/ui/macros/issue-8851.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(dead_code)]
+// after fixing #9384 and implementing hygiene for match bindings,
+// this now fails because the insertion of the 'y' into the match
+// doesn't cause capture. Making this macro hygienic (as I've done)
+// could very well make this test case completely pointless....
+
+// pretty-expanded FIXME #23616
+
+enum T {
+    A(isize),
+    B(usize)
+}
+
+macro_rules! test {
+    ($id:ident, $e:expr) => (
+        fn foo(t: T) -> isize {
+            match t {
+                T::A($id) => $e,
+                T::B($id) => $e
+            }
+        }
+    )
+}
+
+test!(y, 10 + (y as isize));
+
+pub fn main() {
+    foo(T::A(20));
+}
diff --git a/tests/ui/macros/issue-92267.rs b/tests/ui/macros/issue-92267.rs
new file mode 100644
index 00000000000..f1daaeb743e
--- /dev/null
+++ b/tests/ui/macros/issue-92267.rs
@@ -0,0 +1,3 @@
+// check-fail
+
+pub fn main() { println!("🦀%%%", 0) } //~ ERROR argument never used
diff --git a/tests/ui/macros/issue-92267.stderr b/tests/ui/macros/issue-92267.stderr
new file mode 100644
index 00000000000..5359f68cd55
--- /dev/null
+++ b/tests/ui/macros/issue-92267.stderr
@@ -0,0 +1,16 @@
+error: argument never used
+  --> $DIR/issue-92267.rs:3:34
+   |
+LL | pub fn main() { println!("🦀%%%", 0) }
+   |                                   ^ argument never used
+   |
+note: format specifiers use curly braces, and the conversion specifier `
+      ` is unknown or unsupported
+  --> $DIR/issue-92267.rs:3:30
+   |
+LL | pub fn main() { println!("🦀%%%", 0) }
+   |                               ^^
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/issue-95267.rs b/tests/ui/macros/issue-95267.rs
new file mode 100644
index 00000000000..a2fe402bccf
--- /dev/null
+++ b/tests/ui/macros/issue-95267.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// The doc comment here is ignored. This is a bug, but #95267 showed that
+// existing programs rely on this behaviour, and changing it would require some
+// care and a transition period.
+macro_rules! f {
+    (
+        /// ab
+    ) => {};
+}
+
+fn main() {
+    f!();
+}
diff --git a/tests/ui/macros/issue-95533.rs b/tests/ui/macros/issue-95533.rs
new file mode 100644
index 00000000000..905c14dc5fd
--- /dev/null
+++ b/tests/ui/macros/issue-95533.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+#![no_implicit_prelude]
+// the macro should not rely on the prelude being imported
+::std::thread_local! { static P: () = (); }
+::std::thread_local! { static Q: () = const { () }; }
+
+fn main () {}
diff --git a/tests/ui/macros/issue-98466-allow.rs b/tests/ui/macros/issue-98466-allow.rs
new file mode 100644
index 00000000000..c260148c148
--- /dev/null
+++ b/tests/ui/macros/issue-98466-allow.rs
@@ -0,0 +1,16 @@
+// check-pass
+#![allow(named_arguments_used_positionally)]
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {}", _x = 5);
+    println!("_x is {}", y = _x);
+    println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {}", _x = 5);
+    let _f = format!("_x is {}", y = _x);
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+}
diff --git a/tests/ui/macros/issue-98466.fixed b/tests/ui/macros/issue-98466.fixed
new file mode 100644
index 00000000000..e46e22f001f
--- /dev/null
+++ b/tests/ui/macros/issue-98466.fixed
@@ -0,0 +1,51 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {_x}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("_x is {y}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {_x}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("_x is {y}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let s = "0.009";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(".{:0<width$}", s, width = _x);
+
+    let region = "abc";
+    let width = 8;
+    let ls = "abcde";
+    let full = "abcde";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(
+        "| {r:rw$?} | {ui:4?} | {v}",
+        r = region,
+        rw = width,
+        ui = ls,
+        v = full,
+    );
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4);
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4);
+}
diff --git a/tests/ui/macros/issue-98466.rs b/tests/ui/macros/issue-98466.rs
new file mode 100644
index 00000000000..2c3b099afde
--- /dev/null
+++ b/tests/ui/macros/issue-98466.rs
@@ -0,0 +1,51 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    let mut _x: usize;
+    _x = 1;
+    println!("_x is {}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("_x is {}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let mut _x: usize;
+    _x = 1;
+    let _f = format!("_x is {}", _x = 5);
+    //~^ WARNING named argument `_x` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("_x is {}", y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+    //~^ WARNING named argument `y` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    let s = "0.009";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(".{:0<width$}", s, width = _x);
+
+    let region = "abc";
+    let width = 8;
+    let ls = "abcde";
+    let full = "abcde";
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!(
+        "| {r:rw$?} | {ui:4?} | {v}",
+        r = region,
+        rw = width,
+        ui = ls,
+        v = full,
+    );
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4);
+
+    // Confirm that named arguments used in formatting are correctly considered.
+    println!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4);
+}
diff --git a/tests/ui/macros/issue-98466.stderr b/tests/ui/macros/issue-98466.stderr
new file mode 100644
index 00000000000..c93451c761a
--- /dev/null
+++ b/tests/ui/macros/issue-98466.stderr
@@ -0,0 +1,81 @@
+warning: named argument `_x` is not used by name
+  --> $DIR/issue-98466.rs:7:26
+   |
+LL |     println!("_x is {}", _x = 5);
+   |                     --   ^^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `_x` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("_x is {_x}", _x = 5);
+   |                      ++
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:10:26
+   |
+LL |     println!("_x is {}", y = _x);
+   |                     --   ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("_x is {y}", y = _x);
+   |                      +
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:13:83
+   |
+LL |     println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+   |                                                                        --         ^ this named argument is referred to by position in formatting string
+   |                                                                        |
+   |                                                                        this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+   |                                                                         +
+
+warning: named argument `_x` is not used by name
+  --> $DIR/issue-98466.rs:19:34
+   |
+LL |     let _f = format!("_x is {}", _x = 5);
+   |                             --   ^^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `_x` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("_x is {_x}", _x = 5);
+   |                              ++
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:22:34
+   |
+LL |     let _f = format!("_x is {}", y = _x);
+   |                             --   ^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("_x is {y}", y = _x);
+   |                              +
+
+warning: named argument `y` is not used by name
+  --> $DIR/issue-98466.rs:25:91
+   |
+LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
+   |                                                                                --         ^ this named argument is referred to by position in formatting string
+   |                                                                                |
+   |                                                                                this formatting argument uses named argument `y` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x);
+   |                                                                                 +
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/macros/issue-99261.rs b/tests/ui/macros/issue-99261.rs
new file mode 100644
index 00000000000..40d26d08cba
--- /dev/null
+++ b/tests/ui/macros/issue-99261.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+#![deny(named_arguments_used_positionally)]
+
+fn main() {
+    let value: f64 = 314.15926;
+    let digits_before_decimal = 1;
+    let digits_after_decimal = 2;
+    let width = digits_before_decimal + 1 + digits_after_decimal;
+
+    println!(
+        "{value:0>width$.digits_after_decimal$}",
+        value = value,
+        width = width,
+        digits_after_decimal = digits_after_decimal,
+    );
+}
diff --git a/tests/ui/macros/issue-99265.fixed b/tests/ui/macros/issue-99265.fixed
new file mode 100644
index 00000000000..f3be9c6285d
--- /dev/null
+++ b/tests/ui/macros/issue-99265.fixed
@@ -0,0 +1,139 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("{b} {a}", a=1, b=2);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("{} {a} {b} {c} {d}", 0, a=1, b=2, c=3, d=4);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:width$}!", "x", width = 5);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!(
+        "{}, Hello {f:width$.precision$} {g:width2$.precision2$}! {f}",
+        //~^ HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        1,
+        f = 0.02f32,
+        //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+        //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+        width = 5,
+        //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+        precision = 2,
+        //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+        g = 0.02f32,
+        //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally]
+        width2 = 5,
+        //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally
+        precision2 = 2
+        //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("Hello {f:0.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:0.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+
+    let width = 5;
+    let precision = 2;
+    println!("Hello {f:width$.precision$}!", f = 0.02f32);
+
+    let val = 5;
+    println!("{v:v$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{v:v$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{v:v$.v$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{v:v$.v$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("{a} {a} {a}", a = 1);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("aaaaaaaaaaaaaaa\
+                {a:b$.c$}",
+             //~^ HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             a = 1.0, b = 1, c = 2,
+             //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("aaaaaaaaaaaaaaa\
+                {a:b$.c$}",
+             //~^ HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             a = 1.0, b = 1, c = 2,
+             //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("{{{x:width$.precision$}}}", x = 1.0, width = 3, precision = 2);
+    //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/tests/ui/macros/issue-99265.rs b/tests/ui/macros/issue-99265.rs
new file mode 100644
index 00000000000..e7cf608765b
--- /dev/null
+++ b/tests/ui/macros/issue-99265.rs
@@ -0,0 +1,139 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("{b} {}", a=1, b=2);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1$}!", "x", width = 5);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+    //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!(
+        "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+        //~^ HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        //~| HELP use the named argument by name to avoid ambiguity
+        1,
+        f = 0.02f32,
+        //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+        //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+        width = 5,
+        //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally
+        precision = 2,
+        //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+        g = 0.02f32,
+        //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally]
+        width2 = 5,
+        //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally
+        precision2 = 2
+        //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("Hello {:0.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {0:0.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+
+    let width = 5;
+    let precision = 2;
+    println!("Hello {f:width$.precision$}!", f = 0.02f32);
+
+    let val = 5;
+    println!("{:0$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{0:0$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{:0$.0$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    println!("{0:0$.0$}", v = val);
+    //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("{} {a} {0}", a = 1);
+    //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("aaaaaaaaaaaaaaa\
+                {:1$.2$}",
+             //~^ HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             a = 1.0, b = 1, c = 2,
+             //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("aaaaaaaaaaaaaaa\
+                {0:1$.2$}",
+             //~^ HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             //~| HELP use the named argument by name to avoid ambiguity
+             a = 1.0, b = 1, c = 2,
+             //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally]
+             //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally]
+    );
+
+    println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+    //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally]
+    //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/tests/ui/macros/issue-99265.stderr b/tests/ui/macros/issue-99265.stderr
new file mode 100644
index 00000000000..9185dbff61e
--- /dev/null
+++ b/tests/ui/macros/issue-99265.stderr
@@ -0,0 +1,562 @@
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:5:24
+   |
+LL |     println!("{b} {}", a=1, b=2);
+   |                   --   ^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `a` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{b} {a}", a=1, b=2);
+   |                    +
+
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:9:35
+   |
+LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                  --               ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `a` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{} {a} {} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                   +
+
+warning: named argument `b` is not used by name
+  --> $DIR/issue-99265.rs:9:40
+   |
+LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                     --                 ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `b` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{} {} {b} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                      +
+
+warning: named argument `c` is not used by name
+  --> $DIR/issue-99265.rs:9:45
+   |
+LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                        --                   ^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `c` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{} {} {} {c} {}", 0, a=1, b=2, c=3, d=4);
+   |                         +
+
+warning: named argument `d` is not used by name
+  --> $DIR/issue-99265.rs:9:50
+   |
+LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
+   |                           --                     ^ this named argument is referred to by position in formatting string
+   |                           |
+   |                           this formatting argument uses named argument `d` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{} {} {} {} {d}", 0, a=1, b=2, c=3, d=4);
+   |                            +
+
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:19:35
+   |
+LL |     println!("Hello {:1$}!", "x", width = 5);
+   |                       --          ^^^^^ this named argument is referred to by position in formatting string
+   |                       |
+   |                       this formatting argument uses named argument `width` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {:width$}!", "x", width = 5);
+   |                       ~~~~~~
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:23:33
+   |
+LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                     --------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                      +
+
+warning: named argument `precision` is not used by name
+  --> $DIR/issue-99265.rs:23:57
+   |
+LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                          --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
+   |                          |
+   |                          this formatting argument uses named argument `precision` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+   |                          ~~~~~~~~~~
+
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:23:46
+   |
+LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
+   |                       |
+   |                       this formatting argument uses named argument `width` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                       ~~~~~~
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:31:34
+   |
+LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                     ---------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                      ~
+
+warning: named argument `precision` is not used by name
+  --> $DIR/issue-99265.rs:31:58
+   |
+LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                           --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
+   |                           |
+   |                           this formatting argument uses named argument `precision` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2);
+   |                           ~~~~~~~~~~
+
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:31:47
+   |
+LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `width` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2);
+   |                        ~~~~~~
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:49:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                    --------- this formatting argument uses named argument `f` by position
+...
+LL |         f = 0.02f32,
+   |         ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {f:2$.3$} {4:5$.6$}! {1}",
+   |                     ~
+
+warning: named argument `precision` is not used by name
+  --> $DIR/issue-99265.rs:54:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                          -- this formatting argument uses named argument `precision` by position
+...
+LL |         precision = 2,
+   |         ^^^^^^^^^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}",
+   |                          ~~~~~~~~~~
+
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:52:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                       -- this formatting argument uses named argument `width` by position
+...
+LL |         width = 5,
+   |         ^^^^^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:width$.3$} {4:5$.6$}! {1}",
+   |                       ~~~~~~
+
+warning: named argument `g` is not used by name
+  --> $DIR/issue-99265.rs:56:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                              --------- this formatting argument uses named argument `g` by position
+...
+LL |         g = 0.02f32,
+   |         ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:2$.3$} {g:5$.6$}! {1}",
+   |                               ~
+
+warning: named argument `precision2` is not used by name
+  --> $DIR/issue-99265.rs:60:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                                    -- this formatting argument uses named argument `precision2` by position
+...
+LL |         precision2 = 2
+   |         ^^^^^^^^^^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}",
+   |                                    ~~~~~~~~~~~
+
+warning: named argument `width2` is not used by name
+  --> $DIR/issue-99265.rs:58:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                                 -- this formatting argument uses named argument `width2` by position
+...
+LL |         width2 = 5,
+   |         ^^^^^^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}",
+   |                                 ~~~~~~~
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:49:9
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
+   |                                         --- this formatting argument uses named argument `f` by position
+...
+LL |         f = 0.02f32,
+   |         ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {f}",
+   |                                          ~
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:64:31
+   |
+LL |     println!("Hello {:0.1}!", f = 0.02f32);
+   |                     ------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:0.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99265.rs:68:32
+   |
+LL |     println!("Hello {0:0.1}!", f = 0.02f32);
+   |                     -------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:0.1}!", f = 0.02f32);
+   |                      ~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:79:23
+   |
+LL |     println!("{:0$}", v = val);
+   |               -----   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{v:0$}", v = val);
+   |                +
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:79:23
+   |
+LL |     println!("{:0$}", v = val);
+   |                 --    ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{:v$}", v = val);
+   |                 ~~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:84:24
+   |
+LL |     println!("{0:0$}", v = val);
+   |               ------   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{v:0$}", v = val);
+   |                ~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:84:24
+   |
+LL |     println!("{0:0$}", v = val);
+   |                  --    ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{0:v$}", v = val);
+   |                  ~~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:89:26
+   |
+LL |     println!("{:0$.0$}", v = val);
+   |               --------   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{v:0$.0$}", v = val);
+   |                +
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:89:26
+   |
+LL |     println!("{:0$.0$}", v = val);
+   |                    --    ^ this named argument is referred to by position in formatting string
+   |                    |
+   |                    this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{:0$.v$}", v = val);
+   |                    ~~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:89:26
+   |
+LL |     println!("{:0$.0$}", v = val);
+   |                 --       ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{:v$.0$}", v = val);
+   |                 ~~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:96:27
+   |
+LL |     println!("{0:0$.0$}", v = val);
+   |               ---------   ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{v:0$.0$}", v = val);
+   |                ~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:96:27
+   |
+LL |     println!("{0:0$.0$}", v = val);
+   |                     --    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{0:0$.v$}", v = val);
+   |                     ~~
+
+warning: named argument `v` is not used by name
+  --> $DIR/issue-99265.rs:96:27
+   |
+LL |     println!("{0:0$.0$}", v = val);
+   |                  --       ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `v` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{0:v$.0$}", v = val);
+   |                  ~~
+
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:104:28
+   |
+LL |     println!("{} {a} {0}", a = 1);
+   |               --           ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `a` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{a} {a} {0}", a = 1);
+   |                +
+
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:104:28
+   |
+LL |     println!("{} {a} {0}", a = 1);
+   |                      ---   ^ this named argument is referred to by position in formatting string
+   |                      |
+   |                      this formatting argument uses named argument `a` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{} {a} {a}", a = 1);
+   |                       ~
+
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:115:14
+   |
+LL |                 {:1$.2$}",
+   |                 -------- this formatting argument uses named argument `a` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |              ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {a:1$.2$}",
+   |                  +
+
+warning: named argument `c` is not used by name
+  --> $DIR/issue-99265.rs:115:30
+   |
+LL |                 {:1$.2$}",
+   |                      -- this formatting argument uses named argument `c` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |                              ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {:1$.c$}",
+   |                      ~~
+
+warning: named argument `b` is not used by name
+  --> $DIR/issue-99265.rs:115:23
+   |
+LL |                 {:1$.2$}",
+   |                   -- this formatting argument uses named argument `b` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |                       ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {:b$.2$}",
+   |                   ~~
+
+warning: named argument `a` is not used by name
+  --> $DIR/issue-99265.rs:126:14
+   |
+LL |                 {0:1$.2$}",
+   |                 --------- this formatting argument uses named argument `a` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |              ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {a:1$.2$}",
+   |                  ~
+
+warning: named argument `c` is not used by name
+  --> $DIR/issue-99265.rs:126:30
+   |
+LL |                 {0:1$.2$}",
+   |                       -- this formatting argument uses named argument `c` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |                              ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {0:1$.c$}",
+   |                       ~~
+
+warning: named argument `b` is not used by name
+  --> $DIR/issue-99265.rs:126:23
+   |
+LL |                 {0:1$.2$}",
+   |                    -- this formatting argument uses named argument `b` by position
+...
+LL |              a = 1.0, b = 1, c = 2,
+   |                       ^ this named argument is referred to by position in formatting string
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |                 {0:b$.2$}",
+   |                    ~~
+
+warning: named argument `x` is not used by name
+  --> $DIR/issue-99265.rs:132:30
+   |
+LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                 --------     ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `x` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                  +
+
+warning: named argument `precision` is not used by name
+  --> $DIR/issue-99265.rs:132:50
+   |
+LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                      --                          ^^^^^^^^^ this named argument is referred to by position in formatting string
+   |                      |
+   |                      this formatting argument uses named argument `precision` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2);
+   |                      ~~~~~~~~~~
+
+warning: named argument `width` is not used by name
+  --> $DIR/issue-99265.rs:132:39
+   |
+LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `width` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2);
+   |                   ~~~~~~
+
+warning: 42 warnings emitted
+
diff --git a/tests/ui/macros/issue-99907.fixed b/tests/ui/macros/issue-99907.fixed
new file mode 100644
index 00000000000..9e0e1b80ee5
--- /dev/null
+++ b/tests/ui/macros/issue-99907.fixed
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {f:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/tests/ui/macros/issue-99907.rs b/tests/ui/macros/issue-99907.rs
new file mode 100644
index 00000000000..eebcfc2efec
--- /dev/null
+++ b/tests/ui/macros/issue-99907.rs
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello { }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {  }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/tests/ui/macros/issue-99907.stderr b/tests/ui/macros/issue-99907.stderr
new file mode 100644
index 00000000000..eefb28dee35
--- /dev/null
+++ b/tests/ui/macros/issue-99907.stderr
@@ -0,0 +1,68 @@
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:5:30
+   |
+LL |     println!("Hello {:.1}!", f = 0.02f32);
+   |                     -----    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:9:31
+   |
+LL |     println!("Hello {:1.1}!", f = 0.02f32);
+   |                     ------    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:13:27
+   |
+LL |     println!("Hello {}!", f = 0.02f32);
+   |                     --    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:17:28
+   |
+LL |     println!("Hello { }!", f = 0.02f32);
+   |                     ---    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:21:29
+   |
+LL |     println!("Hello {  }!", f = 0.02f32);
+   |                     ----    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs
new file mode 100644
index 00000000000..f8e84756391
--- /dev/null
+++ b/tests/ui/macros/lint-trailing-macro-call.rs
@@ -0,0 +1,16 @@
+// check-pass
+//
+// Ensures that we properly lint
+// a removed 'expression' resulting from a macro
+// in trailing expression position
+
+macro_rules! expand_it {
+    () => {
+        #[cfg(FALSE)] 25; //~  WARN trailing semicolon in macro
+                          //~| WARN this was previously
+    }
+}
+
+fn main() {
+    expand_it!()
+}
diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr
new file mode 100644
index 00000000000..6ab121f7c06
--- /dev/null
+++ b/tests/ui/macros/lint-trailing-macro-call.stderr
@@ -0,0 +1,18 @@
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/lint-trailing-macro-call.rs:9:25
+   |
+LL |         #[cfg(FALSE)] 25;
+   |                         ^
+...
+LL |     expand_it!()
+   |     ------------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `expand_it`
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `expand_it` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs
new file mode 100644
index 00000000000..3967481098c
--- /dev/null
+++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.rs
@@ -0,0 +1,8 @@
+fn main() {}
+
+macro_rules! ambiguity {
+    ($($i:ident)* $j:ident) => {};
+}
+
+ambiguity!(error); //~ ERROR local ambiguity
+ambiguity!(error); //~ ERROR local ambiguity
diff --git a/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr
new file mode 100644
index 00000000000..68b278fd3c8
--- /dev/null
+++ b/tests/ui/macros/local-ambiguity-multiple-parsing-options.stderr
@@ -0,0 +1,14 @@
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+  --> $DIR/local-ambiguity-multiple-parsing-options.rs:7:12
+   |
+LL | ambiguity!(error);
+   |            ^^^^^
+
+error: local ambiguity when calling macro `ambiguity`: multiple parsing options: built-in NTs ident ('i') or ident ('j').
+  --> $DIR/local-ambiguity-multiple-parsing-options.rs:8:12
+   |
+LL | ambiguity!(error);
+   |            ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs b/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs
new file mode 100644
index 00000000000..2d78ae6f908
--- /dev/null
+++ b/tests/ui/macros/log_syntax-trace_macros-macro-locations.rs
@@ -0,0 +1,22 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![feature(trace_macros, log_syntax)]
+
+// make sure these macros can be used as in the various places that
+// macros can occur.
+
+// items
+trace_macros!(false);
+log_syntax!();
+
+fn main() {
+
+    // statements
+    trace_macros!(false);
+    log_syntax!();
+
+    // expressions
+    (trace_macros!(false),
+     log_syntax!());
+}
diff --git a/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout b/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout
new file mode 100644
index 00000000000..b28b04f6431
--- /dev/null
+++ b/tests/ui/macros/log_syntax-trace_macros-macro-locations.stdout
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/ui/macros/macro-2.rs b/tests/ui/macros/macro-2.rs
new file mode 100644
index 00000000000..a315981b6a6
--- /dev/null
+++ b/tests/ui/macros/macro-2.rs
@@ -0,0 +1,12 @@
+// run-pass
+pub fn main() {
+
+    macro_rules! mylambda_tt {
+        ($x:ident, $body:expr) => ({
+            fn f($x: isize) -> isize { return $body; }
+            f
+        })
+    }
+
+    assert_eq!(mylambda_tt!(y, y * 2)(8), 16);
+}
diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs
new file mode 100644
index 00000000000..6781c9a9ed4
--- /dev/null
+++ b/tests/ui/macros/macro-as-fn-body.rs
@@ -0,0 +1,33 @@
+//
+// run-pass
+//
+// Description - ensure Interpolated blocks can act as valid function bodies
+// Covered cases: free functions, struct methods, and default trait functions
+
+macro_rules! def_fn {
+    ($body:block) => {
+        fn bar() $body
+    }
+}
+
+trait Foo {
+    def_fn!({ println!("foo"); });
+}
+
+struct Baz {}
+
+impl Foo for Baz {}
+
+struct Qux {}
+
+impl Qux {
+    def_fn!({ println!("qux"); });
+}
+
+def_fn!({ println!("quux"); });
+
+pub fn main() {
+    Baz::bar();
+    Qux::bar();
+    bar();
+}
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs b/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs
new file mode 100644
index 00000000000..66597c0acf6
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2015-rpass.rs
@@ -0,0 +1,50 @@
+// run-pass
+
+#![allow(unused_mut)]
+
+// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *)
+// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +`
+// or `+` but does not match `pat` or `pat ? pat`.
+
+// edition:2015
+
+macro_rules! foo {
+    // Check for `?`.
+    ($($a:ident)? ? $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `+`.
+    ($($a:ident)? + $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `*`.
+    ($($a:ident)? * $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `;`, not a kleene operator.
+    ($($a:ident)? ; $num:expr) => {
+        let mut x = 0;
+
+        $(
+            x += $a;
+        )?
+
+        assert_eq!(x, $num);
+    };
+}
+
+pub fn main() {
+    let a = 1;
+
+    // Accept 0 repetitions.
+    foo!( ; 0);
+    foo!( + 0);
+    foo!( * 0);
+    foo!( ? 0);
+
+    // Accept 1 repetition.
+    foo!(a ; 1);
+    foo!(a + 1);
+    foo!(a * 1);
+    foo!(a ? 1);
+}
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs
new file mode 100644
index 00000000000..f68100d4557
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs
@@ -0,0 +1,42 @@
+// Tests that `?` is a Kleene op and not a macro separator in the 2015 edition.
+
+// edition:2015
+
+macro_rules! foo {
+    ($(a)?) => {};
+}
+
+// The Kleene op `?` does not admit a separator before it.
+macro_rules! baz {
+    ($(a),?) => {}; //~ERROR the `?` macro repetition operator
+}
+
+macro_rules! barplus {
+    ($(a)?+) => {}; // ok. matches "a+" and "+"
+}
+
+macro_rules! barstar {
+    ($(a)?*) => {}; // ok. matches "a*" and "*"
+}
+
+pub fn main() {
+    foo!();
+    foo!(a);
+    foo!(a?); //~ ERROR no rules expected the token `?`
+    foo!(a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+
+    barplus!(); //~ERROR unexpected end of macro invocation
+    barplus!(a); //~ERROR unexpected end of macro invocation
+    barplus!(a?); //~ ERROR no rules expected the token `?`
+    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a+);
+    barplus!(+);
+
+    barstar!(); //~ERROR unexpected end of macro invocation
+    barstar!(a); //~ERROR unexpected end of macro invocation
+    barstar!(a?); //~ ERROR no rules expected the token `?`
+    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a*);
+    barstar!(*);
+}
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
new file mode 100644
index 00000000000..7c45b85bc8d
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
@@ -0,0 +1,161 @@
+error: the `?` macro repetition operator does not take a separator
+  --> $DIR/macro-at-most-once-rep-2015.rs:11:10
+   |
+LL |     ($(a),?) => {};
+   |          ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:25:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:26:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?a);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:27:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?a?a);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2015.rs:29:5
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!();
+   |     ^^^^^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2015.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2015.rs:30:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a);
+   |               ^ missing tokens in macro arguments
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2015.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:31:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a?);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2015.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:32:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a?a);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2015.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2015.rs:36:5
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!();
+   |     ^^^^^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2015.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2015.rs:37:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a);
+   |               ^ missing tokens in macro arguments
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2015.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:38:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a?);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2015.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2015.rs:39:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a?a);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2015.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs b/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs
new file mode 100644
index 00000000000..b37f3853016
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2018-rpass.rs
@@ -0,0 +1,50 @@
+// run-pass
+
+#![allow(unused_mut)]
+
+// Check that when `?` is followed by what looks like a Kleene operator (?, +, and *)
+// then that `?` is not interpreted as a separator. In other words, `$(pat)?+` matches `pat +`
+// or `+` but does not match `pat` or `pat ? pat`.
+
+// edition:2018
+
+macro_rules! foo {
+    // Check for `?`.
+    ($($a:ident)? ? $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `+`.
+    ($($a:ident)? + $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `*`.
+    ($($a:ident)? * $num:expr) => {
+        foo!($($a)? ; $num);
+    };
+    // Check for `;`, not a kleene operator.
+    ($($a:ident)? ; $num:expr) => {
+        let mut x = 0;
+
+        $(
+            x += $a;
+        )?
+
+        assert_eq!(x, $num);
+    };
+}
+
+pub fn main() {
+    let a = 1;
+
+    // Accept 0 repetitions.
+    foo!( ; 0);
+    foo!( + 0);
+    foo!( * 0);
+    foo!( ? 0);
+
+    // Accept 1 repetition.
+    foo!(a ; 1);
+    foo!(a + 1);
+    foo!(a * 1);
+    foo!(a ? 1);
+}
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs
new file mode 100644
index 00000000000..886a25bbcbc
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs
@@ -0,0 +1,42 @@
+// Tests that `?` is a Kleene op and not a macro separator in the 2018 edition.
+
+// edition:2018
+
+macro_rules! foo {
+    ($(a)?) => {};
+}
+
+// The Kleene op `?` does not admit a separator before it.
+macro_rules! baz {
+    ($(a),?) => {}; //~ERROR the `?` macro repetition operator
+}
+
+macro_rules! barplus {
+    ($(a)?+) => {}; // ok. matches "a+" and "+"
+}
+
+macro_rules! barstar {
+    ($(a)?*) => {}; // ok. matches "a*" and "*"
+}
+
+pub fn main() {
+    foo!();
+    foo!(a);
+    foo!(a?); //~ ERROR no rules expected the token `?`
+    foo!(a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+
+    barplus!(); //~ERROR unexpected end of macro invocation
+    barplus!(a); //~ERROR unexpected end of macro invocation
+    barplus!(a?); //~ ERROR no rules expected the token `?`
+    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a+);
+    barplus!(+);
+
+    barstar!(); //~ERROR unexpected end of macro invocation
+    barstar!(a); //~ERROR unexpected end of macro invocation
+    barstar!(a?); //~ ERROR no rules expected the token `?`
+    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a*);
+    barstar!(*);
+}
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
new file mode 100644
index 00000000000..696520b2826
--- /dev/null
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
@@ -0,0 +1,161 @@
+error: the `?` macro repetition operator does not take a separator
+  --> $DIR/macro-at-most-once-rep-2018.rs:11:10
+   |
+LL |     ($(a),?) => {};
+   |          ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:25:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:26:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?a);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:27:11
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a?a?a);
+   |           ^ no rules expected this token in macro call
+   |
+   = note: while trying to match sequence end
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2018.rs:29:5
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!();
+   |     ^^^^^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2018.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2018.rs:30:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a);
+   |               ^ missing tokens in macro arguments
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2018.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:31:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a?);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2018.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:32:15
+   |
+LL | macro_rules! barplus {
+   | -------------------- when calling this macro
+...
+LL |     barplus!(a?a);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `+`
+  --> $DIR/macro-at-most-once-rep-2018.rs:15:11
+   |
+LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2018.rs:36:5
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!();
+   |     ^^^^^^^^^^ missing tokens in macro arguments
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2018.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-at-most-once-rep-2018.rs:37:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a);
+   |               ^ missing tokens in macro arguments
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2018.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:38:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a?);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2018.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: no rules expected the token `?`
+  --> $DIR/macro-at-most-once-rep-2018.rs:39:15
+   |
+LL | macro_rules! barstar {
+   | -------------------- when calling this macro
+...
+LL |     barstar!(a?a);
+   |               ^ no rules expected this token in macro call
+   |
+note: while trying to match `*`
+  --> $DIR/macro-at-most-once-rep-2018.rs:19:11
+   |
+LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
+   |           ^
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/macros/macro-attribute-expansion.rs b/tests/ui/macros/macro-attribute-expansion.rs
new file mode 100644
index 00000000000..f01e5c44a67
--- /dev/null
+++ b/tests/ui/macros/macro-attribute-expansion.rs
@@ -0,0 +1,16 @@
+// run-pass
+macro_rules! descriptions {
+    ($name:ident is $desc:expr) => {
+        // Check that we will correctly expand attributes
+        #[doc = $desc]
+        #[allow(dead_code)]
+        const $name : &'static str = $desc;
+    }
+}
+
+// item
+descriptions! { DOG is "an animal" }
+descriptions! { RUST is "a language" }
+
+pub fn main() {
+}
diff --git a/tests/ui/macros/macro-attribute.rs b/tests/ui/macros/macro-attribute.rs
new file mode 100644
index 00000000000..88834a96721
--- /dev/null
+++ b/tests/ui/macros/macro-attribute.rs
@@ -0,0 +1,2 @@
+#[doc = $not_there] //~ ERROR expected expression, found `$`
+fn main() { }
diff --git a/tests/ui/macros/macro-attribute.stderr b/tests/ui/macros/macro-attribute.stderr
new file mode 100644
index 00000000000..3316d387264
--- /dev/null
+++ b/tests/ui/macros/macro-attribute.stderr
@@ -0,0 +1,8 @@
+error: expected expression, found `$`
+  --> $DIR/macro-attribute.rs:1:9
+   |
+LL | #[doc = $not_there]
+   |         ^ expected expression
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs
new file mode 100644
index 00000000000..d382e8b7197
--- /dev/null
+++ b/tests/ui/macros/macro-attributes.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+macro_rules! compiles_fine {
+    (#[$at:meta]) => {
+        // test that the different types of attributes work
+        #[attribute]
+        /// Documentation!
+        #[$at]
+
+        // check that the attributes are recognised by requiring this
+        // to be removed to avoid a compile error
+        #[cfg(always_remove)]
+        static MISTYPED: () = "foo";
+    }
+}
+
+// item
+compiles_fine!(#[foo]);
+
+pub fn main() {
+    // statement
+    compiles_fine!(#[bar]);
+}
diff --git a/tests/ui/macros/macro-backtrace-invalid-internals.rs b/tests/ui/macros/macro-backtrace-invalid-internals.rs
new file mode 100644
index 00000000000..9501e7cd07c
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-invalid-internals.rs
@@ -0,0 +1,61 @@
+// Macros in statement vs expression position handle backtraces differently.
+
+macro_rules! fake_method_stmt {
+     () => {
+          1.fake() //~ ERROR no method
+     }
+}
+
+macro_rules! fake_field_stmt {
+     () => {
+          1.fake //~ ERROR doesn't have fields
+     }
+}
+
+macro_rules! fake_anon_field_stmt {
+     () => {
+          (1).0 //~ ERROR doesn't have fields
+     }
+}
+
+macro_rules! fake_method_expr {
+     () => {
+          1.fake() //~ ERROR no method
+     }
+}
+
+macro_rules! fake_field_expr {
+     () => {
+          1.fake //~ ERROR doesn't have fields
+     }
+}
+
+macro_rules! fake_anon_field_expr {
+     () => {
+          (1).0 //~ ERROR doesn't have fields
+     }
+}
+
+macro_rules! real_method_stmt {
+     () => {
+          2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}`
+     }
+}
+
+macro_rules! real_method_expr {
+     () => {
+          2.0.neg() //~ ERROR can't call method `neg` on ambiguous numeric type `{float}`
+     }
+}
+
+fn main() {
+    fake_method_stmt!();
+    fake_field_stmt!();
+    fake_anon_field_stmt!();
+    real_method_stmt!();
+
+    let _ = fake_method_expr!();
+    let _ = fake_field_expr!();
+    let _ = fake_anon_field_expr!();
+    let _ = real_method_expr!();
+}
diff --git a/tests/ui/macros/macro-backtrace-invalid-internals.stderr b/tests/ui/macros/macro-backtrace-invalid-internals.stderr
new file mode 100644
index 00000000000..aa8f06a0df1
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-invalid-internals.stderr
@@ -0,0 +1,100 @@
+error[E0599]: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:5:13
+   |
+LL |           1.fake()
+   |             ^^^^ method not found in `{integer}`
+...
+LL |     fake_method_stmt!();
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `fake_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
+  --> $DIR/macro-backtrace-invalid-internals.rs:11:13
+   |
+LL |           1.fake
+   |             ^^^^
+...
+LL |     fake_field_stmt!();
+   |     ------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `fake_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
+  --> $DIR/macro-backtrace-invalid-internals.rs:17:15
+   |
+LL |           (1).0
+   |               ^
+...
+LL |     fake_anon_field_stmt!();
+   |     ----------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `fake_anon_field_stmt` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0689]: can't call method `neg` on ambiguous numeric type `{float}`
+  --> $DIR/macro-backtrace-invalid-internals.rs:41:15
+   |
+LL |           2.0.neg()
+   |               ^^^
+...
+LL |     real_method_stmt!();
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `real_method_stmt` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you must specify a concrete type for this numeric value, like `f32`
+   |
+LL |           2.0_f32.neg()
+   |           ~~~~~~~
+
+error[E0599]: no method named `fake` found for type `{integer}` in the current scope
+  --> $DIR/macro-backtrace-invalid-internals.rs:23:13
+   |
+LL |           1.fake()
+   |             ^^^^ method not found in `{integer}`
+...
+LL |     let _ = fake_method_expr!();
+   |             ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `fake_method_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
+  --> $DIR/macro-backtrace-invalid-internals.rs:29:13
+   |
+LL |           1.fake
+   |             ^^^^
+...
+LL |     let _ = fake_field_expr!();
+   |             ------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `fake_field_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
+  --> $DIR/macro-backtrace-invalid-internals.rs:35:15
+   |
+LL |           (1).0
+   |               ^
+...
+LL |     let _ = fake_anon_field_expr!();
+   |             ----------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `fake_anon_field_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0689]: can't call method `neg` on ambiguous numeric type `{float}`
+  --> $DIR/macro-backtrace-invalid-internals.rs:47:15
+   |
+LL |           2.0.neg()
+   |               ^^^
+...
+LL |     let _ = real_method_expr!();
+   |             ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `real_method_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you must specify a concrete type for this numeric value, like `f32`
+   |
+LL |           2.0_f32.neg()
+   |           ~~~~~~~
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0599, E0610, E0689.
+For more information about an error, try `rustc --explain E0599`.
diff --git a/tests/ui/macros/macro-backtrace-nested.rs b/tests/ui/macros/macro-backtrace-nested.rs
new file mode 100644
index 00000000000..13d80163dd8
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-nested.rs
@@ -0,0 +1,20 @@
+// In expression position, but not statement position, when we expand a macro,
+// we replace the span of the expanded expression with that of the call site.
+
+macro_rules! nested_expr {
+    () => (fake) //~ ERROR cannot find
+    //~^ ERROR cannot find
+}
+
+macro_rules! call_nested_expr {
+    () => (nested_expr!())
+}
+
+macro_rules! call_nested_expr_sum {
+    () => { 1 + nested_expr!(); }
+}
+
+fn main() {
+    1 + call_nested_expr!();
+    call_nested_expr_sum!();
+}
diff --git a/tests/ui/macros/macro-backtrace-nested.stderr b/tests/ui/macros/macro-backtrace-nested.stderr
new file mode 100644
index 00000000000..dadedfbe8f6
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-nested.stderr
@@ -0,0 +1,25 @@
+error[E0425]: cannot find value `fake` in this scope
+  --> $DIR/macro-backtrace-nested.rs:5:12
+   |
+LL |     () => (fake)
+   |            ^^^^ not found in this scope
+...
+LL |     1 + call_nested_expr!();
+   |         ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `nested_expr` which comes from the expansion of the macro `call_nested_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `fake` in this scope
+  --> $DIR/macro-backtrace-nested.rs:5:12
+   |
+LL |     () => (fake)
+   |            ^^^^ not found in this scope
+...
+LL |     call_nested_expr_sum!();
+   |     ----------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `nested_expr` which comes from the expansion of the macro `call_nested_expr_sum` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/macros/macro-backtrace-println.rs b/tests/ui/macros/macro-backtrace-println.rs
new file mode 100644
index 00000000000..859dd019dcb
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-println.rs
@@ -0,0 +1,19 @@
+// The `format_args!` syntax extension issues errors before code expansion
+// has completed, but we still need a backtrace.
+
+// This test includes stripped-down versions of `print!` and `println!`,
+// because we can't otherwise verify the lines of the backtrace.
+
+fn print(_args: std::fmt::Arguments) {}
+
+macro_rules! myprint {
+    ($($arg:tt)*) => (print(format_args!($($arg)*)));
+}
+
+macro_rules! myprintln {
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR no arguments were given
+}
+
+fn main() {
+    myprintln!("{}");
+}
diff --git a/tests/ui/macros/macro-backtrace-println.stderr b/tests/ui/macros/macro-backtrace-println.stderr
new file mode 100644
index 00000000000..b4e2883e837
--- /dev/null
+++ b/tests/ui/macros/macro-backtrace-println.stderr
@@ -0,0 +1,13 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-backtrace-println.rs:14:30
+   |
+LL |     ($fmt:expr) => (myprint!(concat!($fmt, "\n")));
+   |                              ^^^^^^^^^^^^^^^^^^^
+...
+LL |     myprintln!("{}");
+   |     ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `concat` which comes from the expansion of the macro `myprintln` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-block-nonterminal.rs b/tests/ui/macros/macro-block-nonterminal.rs
new file mode 100644
index 00000000000..a6c9dd6e187
--- /dev/null
+++ b/tests/ui/macros/macro-block-nonterminal.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+macro_rules! do_block{
+    ($val:block) => {$val}
+}
+
+fn main() {
+    let s;
+    do_block!({ s = "it works!"; });
+    assert_eq!(s, "it works!");
+}
diff --git a/tests/ui/macros/macro-comma-behavior-rpass.rs b/tests/ui/macros/macro-comma-behavior-rpass.rs
new file mode 100644
index 00000000000..8406b4e78f6
--- /dev/null
+++ b/tests/ui/macros/macro-comma-behavior-rpass.rs
@@ -0,0 +1,98 @@
+// run-pass
+// needs-unwind
+#![allow(unused_imports)]
+// Ideally, any macro call with a trailing comma should behave
+// identically to a call without the comma.
+//
+// This checks the behavior of macros with trailing commas in key
+// places where regressions in behavior seem highly possible (due
+// to it being e.g., a place where the addition of an argument
+// causes it to go down a code path with subtly different behavior).
+//
+// There is a companion failing test.
+
+// compile-flags: --test -C debug_assertions=yes
+// revisions: std core
+
+#![cfg_attr(core, no_std)]
+
+#[cfg(core)]
+use core::fmt;
+#[cfg(std)]
+use std::fmt;
+
+// an easy mistake in the implementation of 'assert!'
+// would cause this to say "explicit panic"
+#[test]
+#[should_panic(expected = "assertion failed")]
+fn assert_1arg() {
+    assert!(false,);
+}
+
+// same as 'assert_1arg'
+#[test]
+#[should_panic(expected = "assertion failed")]
+fn debug_assert_1arg() {
+    debug_assert!(false,);
+}
+
+// make sure we don't accidentally forward to `write!("text")`
+#[cfg(std)]
+#[test]
+fn writeln_1arg() {
+    use fmt::Write;
+
+    let mut s = String::new();
+    writeln!(&mut s,).unwrap();
+    assert_eq!(&s, "\n");
+}
+
+// A number of format_args-like macros have special-case treatment
+// for a single message string, which is not formatted.
+//
+// This test ensures that the addition of a trailing comma does not
+// suddenly cause these strings to get formatted when they otherwise
+// would not be. This is an easy mistake to make by having such a macro
+// accept ", $($tok:tt)*" instead of ", $($tok:tt)+" after its minimal
+// set of arguments.
+//
+// (Example: Issue #48042)
+#[test]
+#[allow(non_fmt_panics)]
+fn to_format_or_not_to_format() {
+    // ("{}" is the easiest string to test because if this gets
+    // sent to format_args!, it'll simply fail to compile.
+    // "{{}}" is an example of an input that could compile and
+    // produce an incorrect program, but testing the panics
+    // would be burdensome.)
+    let falsum = || false;
+
+    assert!(true, "{}",);
+
+    // assert_eq!(1, 1, "{}",); // see check-fail
+    // assert_ne!(1, 2, "{}",); // see check-fail
+
+    debug_assert!(true, "{}",);
+
+    // debug_assert_eq!(1, 1, "{}",); // see check-fail
+    // debug_assert_ne!(1, 2, "{}",); // see check-fail
+    // eprint!("{}",); // see check-fail
+    // eprintln!("{}",); // see check-fail
+    // format!("{}",); // see check-fail
+    // format_args!("{}",); // see check-fail
+
+    if falsum() {
+        panic!("{}",);
+    }
+
+    // print!("{}",); // see check-fail
+    // println!("{}",); // see check-fail
+    // unimplemented!("{}",); // see check-fail
+
+    if falsum() {
+        unreachable!("{}",);
+    }
+
+    // write!(&mut stdout, "{}",); // see check-fail
+    // writeln!(&mut stdout, "{}",); // see check-fail
+}
diff --git a/tests/ui/macros/macro-comma-behavior.core.stderr b/tests/ui/macros/macro-comma-behavior.core.stderr
new file mode 100644
index 00000000000..ac15e9fa8ea
--- /dev/null
+++ b/tests/ui/macros/macro-comma-behavior.core.stderr
@@ -0,0 +1,50 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:21:23
+   |
+LL |     assert_eq!(1, 1, "{}",);
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:24:23
+   |
+LL |     assert_ne!(1, 2, "{}",);
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:30:29
+   |
+LL |     debug_assert_eq!(1, 1, "{}",);
+   |                             ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:33:29
+   |
+LL |     debug_assert_ne!(1, 2, "{}",);
+   |                             ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:52:19
+   |
+LL |     format_args!("{}",);
+   |                   ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:68:21
+   |
+LL |     unimplemented!("{}",);
+   |                     ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:77:24
+   |
+LL |             write!(f, "{}",)?;
+   |                        ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:81:26
+   |
+LL |             writeln!(f, "{}",)?;
+   |                          ^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/macros/macro-comma-behavior.rs b/tests/ui/macros/macro-comma-behavior.rs
new file mode 100644
index 00000000000..27d50ff3d57
--- /dev/null
+++ b/tests/ui/macros/macro-comma-behavior.rs
@@ -0,0 +1,89 @@
+// Companion test to the similarly-named file in run-pass.
+
+// compile-flags: -C debug_assertions=yes
+// revisions: std core
+
+#![feature(lang_items)]
+#![cfg_attr(core, no_std)]
+
+#[cfg(std)] use std::fmt;
+#[cfg(core)] use core::fmt;
+#[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {}
+#[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0;
+#[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} }
+
+// (see documentation of the similarly-named test in run-pass)
+fn to_format_or_not_to_format() {
+    let falsum = || false;
+
+    // assert!(true, "{}",); // see run-pass
+
+    assert_eq!(1, 1, "{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+    assert_ne!(1, 2, "{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+
+    // debug_assert!(true, "{}",); // see run-pass
+
+    debug_assert_eq!(1, 1, "{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+    debug_assert_ne!(1, 2, "{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+
+    #[cfg(std)] {
+        eprint!("{}",);
+        //[std]~^ ERROR no arguments
+    }
+
+    #[cfg(std)] {
+        eprintln!("{}",);
+        //[std]~^ ERROR no arguments
+    }
+
+    #[cfg(std)] {
+        format!("{}",);
+        //[std]~^ ERROR no arguments
+    }
+
+    format_args!("{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+
+    // if falsum() { panic!("{}",); } // see run-pass
+
+    #[cfg(std)] {
+        print!("{}",);
+        //[std]~^ ERROR no arguments
+    }
+
+    #[cfg(std)] {
+        println!("{}",);
+        //[std]~^ ERROR no arguments
+    }
+
+    unimplemented!("{}",);
+    //[core]~^ ERROR no arguments
+    //[std]~^^ ERROR no arguments
+
+    // if falsum() { unreachable!("{}",); } // see run-pass
+
+    struct S;
+    impl fmt::Display for S {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            write!(f, "{}",)?;
+            //[core]~^ ERROR no arguments
+            //[std]~^^ ERROR no arguments
+
+            writeln!(f, "{}",)?;
+            //[core]~^ ERROR no arguments
+            //[std]~^^ ERROR no arguments
+            Ok(())
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-comma-behavior.std.stderr b/tests/ui/macros/macro-comma-behavior.std.stderr
new file mode 100644
index 00000000000..7fd060e2224
--- /dev/null
+++ b/tests/ui/macros/macro-comma-behavior.std.stderr
@@ -0,0 +1,80 @@
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:21:23
+   |
+LL |     assert_eq!(1, 1, "{}",);
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:24:23
+   |
+LL |     assert_ne!(1, 2, "{}",);
+   |                       ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:30:29
+   |
+LL |     debug_assert_eq!(1, 1, "{}",);
+   |                             ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:33:29
+   |
+LL |     debug_assert_ne!(1, 2, "{}",);
+   |                             ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:38:18
+   |
+LL |         eprint!("{}",);
+   |                  ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:43:20
+   |
+LL |         eprintln!("{}",);
+   |                    ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:48:18
+   |
+LL |         format!("{}",);
+   |                  ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:52:19
+   |
+LL |     format_args!("{}",);
+   |                   ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:59:17
+   |
+LL |         print!("{}",);
+   |                 ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:64:19
+   |
+LL |         println!("{}",);
+   |                   ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:68:21
+   |
+LL |     unimplemented!("{}",);
+   |                     ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:77:24
+   |
+LL |             write!(f, "{}",)?;
+   |                        ^^
+
+error: 1 positional argument in format string, but no arguments were given
+  --> $DIR/macro-comma-behavior.rs:81:26
+   |
+LL |             writeln!(f, "{}",)?;
+   |                          ^^
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/ui/macros/macro-comma-support-rpass.rs b/tests/ui/macros/macro-comma-support-rpass.rs
new file mode 100644
index 00000000000..25b8c3cc62e
--- /dev/null
+++ b/tests/ui/macros/macro-comma-support-rpass.rs
@@ -0,0 +1,355 @@
+// run-pass
+// This is meant to be a comprehensive test of invocations with/without
+// trailing commas (or other, similar optionally-trailing separators).
+// Every macro is accounted for, even those not tested in this file.
+// (There will be a note indicating why).
+
+// std and core are both tested because they may contain separate
+// implementations for some macro_rules! macros as an implementation
+// detail.
+
+// ignore-pretty issue #37195
+
+// compile-flags: --test -C debug_assertions=yes
+// revisions: std core
+
+#![cfg_attr(core, no_std)]
+
+#![allow(deprecated)] // for deprecated `try!()` macro
+#![feature(concat_idents)]
+
+#[cfg(std)] use std::fmt;
+#[cfg(core)] use core::fmt;
+
+#[test]
+fn assert() {
+    assert!(true);
+    assert!(true,);
+    assert!(true, "hello");
+    assert!(true, "hello",);
+    assert!(true, "hello {}", "world");
+    assert!(true, "hello {}", "world",);
+}
+
+#[test]
+fn assert_eq() {
+    assert_eq!(1, 1);
+    assert_eq!(1, 1,);
+    assert_eq!(1, 1, "hello");
+    assert_eq!(1, 1, "hello",);
+    assert_eq!(1, 1, "hello {}", "world");
+    assert_eq!(1, 1, "hello {}", "world",);
+}
+
+#[test]
+fn assert_ne() {
+    assert_ne!(1, 2);
+    assert_ne!(1, 2,);
+    assert_ne!(1, 2, "hello");
+    assert_ne!(1, 2, "hello",);
+    assert_ne!(1, 2, "hello {}", "world");
+    assert_ne!(1, 2, "hello {}", "world",);
+}
+
+#[test]
+fn cfg() {
+    let _ = cfg!(pants);
+    let _ = cfg!(pants,);
+    let _ = cfg!(pants = "pants");
+    let _ = cfg!(pants = "pants",);
+    let _ = cfg!(all(pants));
+    let _ = cfg!(all(pants),);
+    let _ = cfg!(all(pants,));
+    let _ = cfg!(all(pants,),);
+}
+
+#[test]
+fn column() {
+    let _ = column!();
+}
+
+// compile_error! is in a check-fail companion to this test
+
+#[test]
+fn concat() {
+    let _ = concat!();
+    let _ = concat!("hello");
+    let _ = concat!("hello",);
+    let _ = concat!("hello", " world");
+    let _ = concat!("hello", " world",);
+}
+
+#[test]
+fn concat_idents() {
+    fn foo() {}
+    fn foobar() {}
+
+    concat_idents!(foo)();
+    concat_idents!(foo,)();
+    concat_idents!(foo, bar)();
+    concat_idents!(foo, bar,)();
+}
+
+#[test]
+fn debug_assert() {
+    debug_assert!(true);
+    debug_assert!(true, );
+    debug_assert!(true, "hello");
+    debug_assert!(true, "hello",);
+    debug_assert!(true, "hello {}", "world");
+    debug_assert!(true, "hello {}", "world",);
+}
+
+#[test]
+fn debug_assert_eq() {
+    debug_assert_eq!(1, 1);
+    debug_assert_eq!(1, 1,);
+    debug_assert_eq!(1, 1, "hello");
+    debug_assert_eq!(1, 1, "hello",);
+    debug_assert_eq!(1, 1, "hello {}", "world");
+    debug_assert_eq!(1, 1, "hello {}", "world",);
+}
+
+#[test]
+fn debug_assert_ne() {
+    debug_assert_ne!(1, 2);
+    debug_assert_ne!(1, 2,);
+    debug_assert_ne!(1, 2, "hello");
+    debug_assert_ne!(1, 2, "hello",);
+    debug_assert_ne!(1, 2, "hello {}", "world");
+    debug_assert_ne!(1, 2, "hello {}", "world",);
+}
+
+#[test]
+fn env() {
+    let _ = env!("PATH");
+    let _ = env!("PATH",);
+    let _ = env!("PATH", "not found");
+    let _ = env!("PATH", "not found",);
+}
+
+#[cfg(std)]
+#[test]
+fn eprint() {
+    eprint!("hello");
+    eprint!("hello",);
+    eprint!("hello {}", "world");
+    eprint!("hello {}", "world",);
+}
+
+#[cfg(std)]
+#[test]
+fn eprintln() {
+    eprintln!();
+    eprintln!("hello");
+    eprintln!("hello",);
+    eprintln!("hello {}", "world");
+    eprintln!("hello {}", "world",);
+}
+
+#[test]
+fn file() {
+    let _ = file!();
+}
+
+#[cfg(std)]
+#[test]
+fn format() {
+    let _ = format!("hello");
+    let _ = format!("hello",);
+    let _ = format!("hello {}", "world");
+    let _ = format!("hello {}", "world",);
+}
+
+#[test]
+fn format_args() {
+    let _ = format_args!("hello");
+    let _ = format_args!("hello",);
+    let _ = format_args!("hello {}", "world");
+    let _ = format_args!("hello {}", "world",);
+}
+
+#[test]
+fn include() {
+    let _ = include!("auxiliary/macro-comma-support.rs");
+    let _ = include!("auxiliary/macro-comma-support.rs",);
+}
+
+#[test]
+fn include_bytes() {
+    let _ = include_bytes!("auxiliary/macro-comma-support.rs");
+    let _ = include_bytes!("auxiliary/macro-comma-support.rs",);
+}
+
+#[test]
+fn include_str() {
+    let _ = include_str!("auxiliary/macro-comma-support.rs");
+    let _ = include_str!("auxiliary/macro-comma-support.rs",);
+}
+
+#[test]
+fn line() {
+    let _ = line!();
+}
+
+#[test]
+fn matches() {
+    let _ = matches!(1, x if x > 0);
+    let _ = matches!(1, x if x > 0,);
+}
+
+#[test]
+fn module_path() {
+    let _ = module_path!();
+}
+
+#[test]
+fn option_env() {
+    let _ = option_env!("PATH");
+    let _ = option_env!("PATH",);
+}
+
+#[test]
+fn panic() {
+    // prevent 'unreachable code' warnings
+    let falsum = || false;
+
+    if falsum() { panic!(); }
+    if falsum() { panic!("hello"); }
+    if falsum() { panic!("hello",); }
+    if falsum() { panic!("hello {}", "world"); }
+    if falsum() { panic!("hello {}", "world",); }
+}
+
+#[cfg(std)]
+#[test]
+fn print() {
+    print!("hello");
+    print!("hello",);
+    print!("hello {}", "world");
+    print!("hello {}", "world",);
+}
+
+#[cfg(std)]
+#[test]
+fn println() {
+    println!();
+    println!("hello");
+    println!("hello",);
+    println!("hello {}", "world");
+    println!("hello {}", "world",);
+}
+
+// stringify! is N/A
+
+#[cfg(std)]
+#[test]
+fn thread_local() {
+    // this has an optional trailing *semicolon*
+    thread_local! {
+        #[allow(unused)] pub static A: () = ()
+    }
+
+    thread_local! {
+        #[allow(unused)] pub static AA: () = ();
+    }
+
+    thread_local! {
+        #[allow(unused)] pub static AAA: () = ();
+        #[allow(unused)] pub static AAAA: () = ()
+    }
+
+    thread_local! {
+        #[allow(unused)] pub static AAAAG: () = ();
+        #[allow(unused)] pub static AAAAGH: () = ();
+    }
+}
+
+#[test]
+fn try() {
+    fn inner() -> Result<(), ()> {
+        try!(Ok(()));
+        try!(Ok(()),);
+        Ok(())
+    }
+
+    inner().unwrap();
+}
+
+#[test]
+fn unimplemented() {
+    // prevent 'unreachable code' warnings
+    let falsum = || false;
+
+    if falsum() { unimplemented!(); }
+    if falsum() { unimplemented!("hello"); }
+    if falsum() { unimplemented!("hello",); }
+    if falsum() { unimplemented!("hello {}", "world"); }
+    if falsum() { unimplemented!("hello {}", "world",); }
+}
+
+#[test]
+fn unreachable() {
+    // prevent 'unreachable code' warnings
+    let falsum = || false;
+
+    if falsum() { unreachable!(); }
+    if falsum() { unreachable!("hello"); }
+    if falsum() { unreachable!("hello",); }
+    if falsum() { unreachable!("hello {}", "world"); }
+    if falsum() { unreachable!("hello {}", "world",); }
+}
+
+#[cfg(std)]
+#[test]
+fn vec() {
+    let _: Vec<()> = vec![];
+    let _ = vec![0];
+    let _ = vec![0,];
+    let _ = vec![0, 1];
+    let _ = vec![0, 1,];
+}
+
+// give a test body access to a fmt::Formatter, which seems
+// to be the easiest way to use 'write!' on core.
+macro_rules! test_with_formatter {
+    (
+        #[test]
+        fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block
+    ) => {
+        #[test]
+        fn $fname() {
+            struct Struct;
+            impl fmt::Display for Struct {
+                fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result {
+                    Ok($block)
+                }
+            }
+
+            // suppress "unused"
+            assert!(true, "{}", Struct);
+        }
+    };
+}
+
+test_with_formatter! {
+    #[test]
+    fn write(f: &mut fmt::Formatter) {
+        let _ = write!(f, "hello");
+        let _ = write!(f, "hello",);
+        let _ = write!(f, "hello {}", "world");
+        let _ = write!(f, "hello {}", "world",);
+    }
+}
+
+test_with_formatter! {
+    #[test]
+    fn writeln(f: &mut fmt::Formatter) {
+        let _ = writeln!(f);
+        let _ = writeln!(f,);
+        let _ = writeln!(f, "hello");
+        let _ = writeln!(f, "hello",);
+        let _ = writeln!(f, "hello {}", "world");
+        let _ = writeln!(f, "hello {}", "world",);
+    }
+}
diff --git a/tests/ui/macros/macro-comma-support.rs b/tests/ui/macros/macro-comma-support.rs
new file mode 100644
index 00000000000..7df5b62339f
--- /dev/null
+++ b/tests/ui/macros/macro-comma-support.rs
@@ -0,0 +1,10 @@
+// This is a companion to the similarly-named test in run-pass.
+//
+// It tests macros that unavoidably produce compile errors.
+
+fn compile_error() {
+    compile_error!("lel"); //~ ERROR lel
+    compile_error!("lel",); //~ ERROR lel
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-comma-support.stderr b/tests/ui/macros/macro-comma-support.stderr
new file mode 100644
index 00000000000..874efccd323
--- /dev/null
+++ b/tests/ui/macros/macro-comma-support.stderr
@@ -0,0 +1,14 @@
+error: lel
+  --> $DIR/macro-comma-support.rs:6:5
+   |
+LL |     compile_error!("lel");
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: lel
+  --> $DIR/macro-comma-support.rs:7:5
+   |
+LL |     compile_error!("lel",);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs
new file mode 100644
index 00000000000..d09fdf118e6
--- /dev/null
+++ b/tests/ui/macros/macro-context.rs
@@ -0,0 +1,21 @@
+// (typeof used because it's surprisingly hard to find an unparsed token after a stmt)
+macro_rules! m {
+    () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
+                            //~| ERROR macro expansion ignores token `typeof`
+                            //~| ERROR macro expansion ignores token `;`
+                            //~| ERROR macro expansion ignores token `;`
+                            //~| ERROR cannot find type `i` in this scope
+                            //~| ERROR cannot find value `i` in this scope
+                            //~| WARN trailing semicolon in macro
+                            //~| WARN this was previously
+}
+
+fn main() {
+    let a: m!();
+    let i = m!();
+    match 0 {
+        m!() => {}
+    }
+
+    m!();
+}
diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr
new file mode 100644
index 00000000000..f597c398b7c
--- /dev/null
+++ b/tests/ui/macros/macro-context.stderr
@@ -0,0 +1,84 @@
+error: macro expansion ignores token `;` and any following
+  --> $DIR/macro-context.rs:3:15
+   |
+LL |     () => ( i ; typeof );
+   |               ^
+...
+LL |     let a: m!();
+   |            ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in type context
+
+error: macro expansion ignores token `typeof` and any following
+  --> $DIR/macro-context.rs:3:17
+   |
+LL |     () => ( i ; typeof );
+   |                 ^^^^^^
+...
+LL |     let i = m!();
+   |             ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in expression context
+
+error: macro expansion ignores token `;` and any following
+  --> $DIR/macro-context.rs:3:15
+   |
+LL |     () => ( i ; typeof );
+   |               ^
+...
+LL |         m!() => {}
+   |         ---- caused by the macro expansion here
+   |
+   = note: the usage of `m!` is likely invalid in pattern context
+
+error: expected expression, found reserved keyword `typeof`
+  --> $DIR/macro-context.rs:3:17
+   |
+LL |     () => ( i ; typeof );
+   |                 ^^^^^^ expected expression
+...
+LL |     m!();
+   |     ---- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0412]: cannot find type `i` in this scope
+  --> $DIR/macro-context.rs:3:13
+   |
+LL |     () => ( i ; typeof );
+   |             ^ help: a builtin type with a similar name exists: `i8`
+...
+LL |     let a: m!();
+   |            ---- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/macro-context.rs:3:13
+   |
+LL |     () => ( i ; typeof );
+   |             ^ not found in this scope
+...
+LL |     let i = m!();
+   |             ---- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/macro-context.rs:3:15
+   |
+LL |     () => ( i ; typeof );
+   |               ^
+...
+LL |     let i = m!();
+   |             ---- in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0412, E0425.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/macros/macro-crate-def-only.rs b/tests/ui/macros/macro-crate-def-only.rs
new file mode 100644
index 00000000000..514b33e3897
--- /dev/null
+++ b/tests/ui/macros/macro-crate-def-only.rs
@@ -0,0 +1,10 @@
+// run-pass
+// aux-build:macro_crate_def_only.rs
+
+
+#[macro_use] #[no_link]
+extern crate macro_crate_def_only;
+
+pub fn main() {
+    assert_eq!(5, make_a_5!());
+}
diff --git a/tests/ui/macros/macro-crate-nonterminal-non-root.rs b/tests/ui/macros/macro-crate-nonterminal-non-root.rs
new file mode 100644
index 00000000000..67899556f8a
--- /dev/null
+++ b/tests/ui/macros/macro-crate-nonterminal-non-root.rs
@@ -0,0 +1,9 @@
+// aux-build:macro_crate_nonterminal.rs
+
+mod foo {
+    #[macro_use]
+    extern crate macro_crate_nonterminal;  //~ ERROR must be at the crate root
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/macro-crate-nonterminal-non-root.stderr b/tests/ui/macros/macro-crate-nonterminal-non-root.stderr
new file mode 100644
index 00000000000..1eca0186da9
--- /dev/null
+++ b/tests/ui/macros/macro-crate-nonterminal-non-root.stderr
@@ -0,0 +1,9 @@
+error[E0468]: an `extern crate` loading macros must be at the crate root
+  --> $DIR/macro-crate-nonterminal-non-root.rs:5:5
+   |
+LL |     extern crate macro_crate_nonterminal;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0468`.
diff --git a/tests/ui/macros/macro-crate-nonterminal-renamed.rs b/tests/ui/macros/macro-crate-nonterminal-renamed.rs
new file mode 100644
index 00000000000..87bd397f065
--- /dev/null
+++ b/tests/ui/macros/macro-crate-nonterminal-renamed.rs
@@ -0,0 +1,10 @@
+// run-pass
+// aux-build:macro_crate_nonterminal.rs
+
+#[macro_use]
+extern crate macro_crate_nonterminal as new_name;
+
+pub fn main() {
+    new_name::check_local();
+    assert_eq!(increment!(5), 6);
+}
diff --git a/tests/ui/macros/macro-crate-nonterminal.rs b/tests/ui/macros/macro-crate-nonterminal.rs
new file mode 100644
index 00000000000..4b1056fc725
--- /dev/null
+++ b/tests/ui/macros/macro-crate-nonterminal.rs
@@ -0,0 +1,10 @@
+// run-pass
+// aux-build:macro_crate_nonterminal.rs
+
+#[macro_use]
+extern crate macro_crate_nonterminal;
+
+pub fn main() {
+    macro_crate_nonterminal::check_local();
+    assert_eq!(increment!(5), 6);
+}
diff --git a/tests/ui/macros/macro-crate-use.rs b/tests/ui/macros/macro-crate-use.rs
new file mode 100644
index 00000000000..5c37cac9686
--- /dev/null
+++ b/tests/ui/macros/macro-crate-use.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+pub fn increment(x: usize) -> usize {
+    x + 1
+}
+
+#[macro_export]
+macro_rules! increment {
+    ($x:expr) => ({
+        use $crate::increment;
+        increment($x)
+    })
+}
+
+fn main() {
+    assert_eq!(increment!(3), 4);
+}
diff --git a/tests/ui/macros/macro-deep_expansion.rs b/tests/ui/macros/macro-deep_expansion.rs
new file mode 100644
index 00000000000..e13d8e1fc84
--- /dev/null
+++ b/tests/ui/macros/macro-deep_expansion.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+macro_rules! foo2 {
+    () => {
+        "foo"
+    }
+}
+
+macro_rules! foo {
+    () => {
+        foo2!()
+    }
+}
+
+fn main() {
+    assert_eq!(concat!(foo!(), "bar"), "foobar")
+}
diff --git a/tests/ui/macros/macro-def-site-super.rs b/tests/ui/macros/macro-def-site-super.rs
new file mode 100644
index 00000000000..716a8ced5bb
--- /dev/null
+++ b/tests/ui/macros/macro-def-site-super.rs
@@ -0,0 +1,10 @@
+// `super` in a `macro` refers to the parent module of the macro itself and not its reexport.
+
+// check-pass
+// aux-build:macro-def-site-super.rs
+
+extern crate macro_def_site_super;
+
+type A = macro_def_site_super::public::mac!();
+
+fn main() {}
diff --git a/tests/ui/macros/macro-delimiter-significance.rs b/tests/ui/macros/macro-delimiter-significance.rs
new file mode 100644
index 00000000000..89f222b0530
--- /dev/null
+++ b/tests/ui/macros/macro-delimiter-significance.rs
@@ -0,0 +1,4 @@
+// run-pass
+fn main() {
+    vec![1_usize, 2, 3].len();
+}
diff --git a/tests/ui/macros/macro-deprecation.rs b/tests/ui/macros/macro-deprecation.rs
new file mode 100644
index 00000000000..a7f327cf53b
--- /dev/null
+++ b/tests/ui/macros/macro-deprecation.rs
@@ -0,0 +1,13 @@
+// check-pass
+// aux-build:deprecated-macros.rs
+
+#[macro_use] extern crate deprecated_macros;
+
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
+#[macro_export]
+macro_rules! local_deprecated{ () => () }
+
+fn main() {
+    local_deprecated!(); //~ WARN use of deprecated macro `local_deprecated`: local deprecation note
+    deprecated_macro!(); //~ WARN use of deprecated macro `deprecated_macro`: deprecation note
+}
diff --git a/tests/ui/macros/macro-deprecation.stderr b/tests/ui/macros/macro-deprecation.stderr
new file mode 100644
index 00000000000..07849d7ce57
--- /dev/null
+++ b/tests/ui/macros/macro-deprecation.stderr
@@ -0,0 +1,16 @@
+warning: use of deprecated macro `local_deprecated`: local deprecation note
+  --> $DIR/macro-deprecation.rs:11:5
+   |
+LL |     local_deprecated!();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+warning: use of deprecated macro `deprecated_macro`: deprecation note
+  --> $DIR/macro-deprecation.rs:12:5
+   |
+LL |     deprecated_macro!();
+   |     ^^^^^^^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/macros/macro-doc-comments.rs b/tests/ui/macros/macro-doc-comments.rs
new file mode 100644
index 00000000000..fcc64cc0670
--- /dev/null
+++ b/tests/ui/macros/macro-doc-comments.rs
@@ -0,0 +1,26 @@
+// run-pass
+#![allow(non_snake_case)]
+
+macro_rules! doc {
+    (
+        $(#[$outer:meta])*
+        mod $i:ident {
+            $(#![$inner:meta])*
+        }
+    ) =>
+    (
+        $(#[$outer])*
+        pub mod $i {
+            $(#![$inner])*
+        }
+    )
+}
+
+doc! {
+    /// Outer doc
+    mod Foo {
+        //! Inner doc
+    }
+}
+
+fn main() { }
diff --git a/tests/ui/macros/macro-doc-escapes.rs b/tests/ui/macros/macro-doc-escapes.rs
new file mode 100644
index 00000000000..ff5a5793b20
--- /dev/null
+++ b/tests/ui/macros/macro-doc-escapes.rs
@@ -0,0 +1,16 @@
+// run-pass
+// When expanding a macro, documentation attributes (including documentation comments) must be
+// passed "as is" without being parsed. Otherwise, some text will be incorrectly interpreted as
+// escape sequences, leading to an ICE.
+//
+// Related issues: #25929, #25943
+
+macro_rules! homura {
+    (#[$x:meta]) => ()
+}
+
+homura! {
+    /// \madoka \x41
+}
+
+fn main() { }
diff --git a/tests/ui/macros/macro-doc-raw-str-hashes.rs b/tests/ui/macros/macro-doc-raw-str-hashes.rs
new file mode 100644
index 00000000000..a003bff3c04
--- /dev/null
+++ b/tests/ui/macros/macro-doc-raw-str-hashes.rs
@@ -0,0 +1,30 @@
+// run-pass
+// The number of `#`s used to wrap the documentation comment should differ regarding the content.
+//
+// Related issue: #27489
+
+macro_rules! homura {
+    ($x:expr, #[$y:meta]) => (assert_eq!($x, stringify!($y)))
+}
+
+fn main() {
+    homura! {
+        r#"doc = r" Madoka""#,
+        /// Madoka
+    };
+
+    homura! {
+        r##"doc = r#" One quote mark: ["]"#"##,
+        /// One quote mark: ["]
+    };
+
+    homura! {
+        r##"doc = r#" Two quote marks: [""]"#"##,
+        /// Two quote marks: [""]
+    };
+
+    homura! {
+        r#####"doc = r####" Raw string ending sequences: ["###]"####"#####,
+        /// Raw string ending sequences: ["###]
+    };
+}
diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs
new file mode 100644
index 00000000000..59ed79e91f0
--- /dev/null
+++ b/tests/ui/macros/macro-error.rs
@@ -0,0 +1,9 @@
+macro_rules! foo {
+    ($a:expr) => a; //~ ERROR macro rhs must be delimited
+}
+
+fn main() {
+    foo!(0); // Check that we report errors at macro definition, not expansion.
+
+    let _: cfg!(foo) = (); //~ ERROR non-type macro in type position
+}
diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr
new file mode 100644
index 00000000000..2539a6d5156
--- /dev/null
+++ b/tests/ui/macros/macro-error.stderr
@@ -0,0 +1,14 @@
+error: macro rhs must be delimited
+  --> $DIR/macro-error.rs:2:18
+   |
+LL |     ($a:expr) => a;
+   |                  ^
+
+error: non-type macro in type position: cfg
+  --> $DIR/macro-error.rs:8:12
+   |
+LL |     let _: cfg!(foo) = ();
+   |            ^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-expanded-include/file.txt b/tests/ui/macros/macro-expanded-include/file.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tests/ui/macros/macro-expanded-include/file.txt
diff --git a/tests/ui/macros/macro-expanded-include/foo/mod.rs b/tests/ui/macros/macro-expanded-include/foo/mod.rs
new file mode 100644
index 00000000000..cff110470f2
--- /dev/null
+++ b/tests/ui/macros/macro-expanded-include/foo/mod.rs
@@ -0,0 +1,9 @@
+// ignore-test
+
+macro_rules! m {
+    () => { include!("file.txt"); }
+}
+
+macro_rules! n {
+    () => { unsafe { core::arch::asm!(include_str!("file.txt")); } }
+}
diff --git a/tests/ui/macros/macro-expanded-include/test.rs b/tests/ui/macros/macro-expanded-include/test.rs
new file mode 100644
index 00000000000..20da58a7e8e
--- /dev/null
+++ b/tests/ui/macros/macro-expanded-include/test.rs
@@ -0,0 +1,13 @@
+// needs-asm-support
+// build-pass (FIXME(62277): could be check-pass?)
+#![allow(unused)]
+
+#[macro_use]
+mod foo;
+
+m!();
+fn f() {
+    n!();
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-expansion-tests.rs b/tests/ui/macros/macro-expansion-tests.rs
new file mode 100644
index 00000000000..38f4937c127
--- /dev/null
+++ b/tests/ui/macros/macro-expansion-tests.rs
@@ -0,0 +1,40 @@
+#![allow(unused_macros)]
+
+mod macros_cant_escape_fns {
+    fn f() {
+        macro_rules! m { () => { 3 + 4 } }
+    }
+    fn g() -> i32 { m!() }
+    //~^ ERROR cannot find macro
+}
+
+mod macros_cant_escape_mods {
+    mod f {
+        macro_rules! m { () => { 3 + 4 } }
+    }
+    fn g() -> i32 { m!() }
+    //~^ ERROR cannot find macro
+}
+
+mod macros_can_escape_flattened_mods_test {
+    #[macro_use]
+    mod f {
+        macro_rules! m { () => { 3 + 4 } }
+    }
+    fn g() -> i32 { m!() }
+}
+
+fn macro_tokens_should_match() {
+    macro_rules! m { (a) => { 13 } }
+    m!(a);
+}
+
+// should be able to use a bound identifier as a literal in a macro definition:
+fn self_macro_parsing() {
+    macro_rules! foo { (zz) => { 287; } }
+    fn f(zz: i32) {
+        foo!(zz);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-expansion-tests.stderr b/tests/ui/macros/macro-expansion-tests.stderr
new file mode 100644
index 00000000000..8b3f7ca8817
--- /dev/null
+++ b/tests/ui/macros/macro-expansion-tests.stderr
@@ -0,0 +1,18 @@
+error: cannot find macro `m` in this scope
+  --> $DIR/macro-expansion-tests.rs:7:21
+   |
+LL |     fn g() -> i32 { m!() }
+   |                     ^
+   |
+   = help: have you added the `#[macro_use]` on the module/import?
+
+error: cannot find macro `m` in this scope
+  --> $DIR/macro-expansion-tests.rs:15:21
+   |
+LL |     fn g() -> i32 { m!() }
+   |                     ^
+   |
+   = help: have you added the `#[macro_use]` on the module/import?
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-export-inner-module.rs b/tests/ui/macros/macro-export-inner-module.rs
new file mode 100644
index 00000000000..1f23e90b65c
--- /dev/null
+++ b/tests/ui/macros/macro-export-inner-module.rs
@@ -0,0 +1,9 @@
+// run-pass
+//aux-build:macro_export_inner_module.rs
+
+#[macro_use] #[no_link]
+extern crate macro_export_inner_module;
+
+pub fn main() {
+    assert_eq!(1, foo!());
+}
diff --git a/tests/ui/macros/macro-first-set.rs b/tests/ui/macros/macro-first-set.rs
new file mode 100644
index 00000000000..eeb1ddd84ae
--- /dev/null
+++ b/tests/ui/macros/macro-first-set.rs
@@ -0,0 +1,272 @@
+// run-pass
+#![allow(unused_macro_rules)]
+
+//{{{ issue 40569 ==============================================================
+
+macro_rules! my_struct {
+    ($(#[$meta:meta])* $ident:ident) => {
+        $(#[$meta])* struct $ident;
+    }
+}
+
+my_struct!(#[derive(Debug, PartialEq)] Foo40569);
+
+fn test_40569() {
+    assert_eq!(Foo40569, Foo40569);
+}
+
+//}}}
+
+//{{{ issue 26444 ==============================================================
+
+macro_rules! foo_26444 {
+    ($($beginning:ident),*; $middle:ident; $($end:ident),*) => {
+        stringify!($($beginning,)* $middle $(,$end)*)
+    }
+}
+
+fn test_26444() {
+    assert_eq!("a, b, c, d, e", foo_26444!(a, b; c; d, e));
+    assert_eq!("f", foo_26444!(; f ;));
+}
+
+macro_rules! pat_26444 {
+    ($fname:ident $($arg:pat)* =) => {}
+}
+
+pat_26444!(foo 1 2 5...7 =);
+pat_26444!(bar Some(ref x) Ok(ref mut y) &(w, z) =);
+
+//}}}
+
+//{{{ issue 40984 ==============================================================
+
+macro_rules! thread_local_40984 {
+    () => {};
+    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => {
+        thread_local_40984!($($rest)*);
+    };
+    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => {};
+}
+
+thread_local_40984! {
+    // no docs
+    #[allow(unused)]
+    static FOO: i32 = 42;
+    /// docs
+    pub static BAR: String = String::from("bar");
+
+    // look at these restrictions!!
+    pub(crate) static BAZ: usize = 0;
+    pub(in foo) static QUUX: usize = 0;
+}
+
+//}}}
+
+//{{{ issue 35650 ==============================================================
+
+macro_rules! size {
+    ($ty:ty) => {
+        std::mem::size_of::<$ty>()
+    };
+    ($size:tt) => {
+        $size
+    };
+}
+
+fn test_35650() {
+    assert_eq!(size!(u64), 8);
+    assert_eq!(size!(5), 5);
+}
+
+//}}}
+
+//{{{ issue 27832 ==============================================================
+
+macro_rules! m {
+    ( $i:ident ) => ();
+    ( $t:tt $j:tt ) => ();
+}
+
+m!(c);
+m!(t 9);
+m!(0 9);
+m!(struct);
+m!(struct Foo);
+
+macro_rules! m2 {
+    ( $b:expr ) => ();
+    ( $t:tt $u:tt ) => ();
+}
+
+m2!(3);
+m2!(1 2);
+m2!(_ 1);
+m2!(enum Foo);
+
+//}}}
+
+//{{{ issue 39964 ==============================================================
+
+macro_rules! foo_39964 {
+    ($a:ident) => {};
+    (_) => {};
+}
+
+foo_39964!(_);
+
+//}}}
+
+//{{{ issue 34030 ==============================================================
+
+macro_rules! foo_34030 {
+    ($($t:ident),* /) => {};
+}
+
+foo_34030!(a, b/);
+foo_34030!(a/);
+foo_34030!(/);
+
+//}}}
+
+//{{{ issue 24189 ==============================================================
+
+macro_rules! foo_24189 {
+    (
+        pub enum $name:ident {
+            $( #[$attr:meta] )* $var:ident
+        }
+    ) => {
+        pub enum $name {
+            $( #[$attr] )* $var
+        }
+    };
+}
+
+foo_24189! {
+    pub enum Foo24189 {
+        #[doc = "Bar"] Baz
+    }
+}
+
+macro_rules! serializable {
+    (
+        $(#[$struct_meta:meta])*
+        pub struct $name:ident {
+            $(
+                $(#[$field_meta:meta])*
+                $field:ident: $type_:ty
+            ),* ,
+        }
+    ) => {
+        $(#[$struct_meta])*
+        pub struct $name {
+            $(
+                $(#[$field_meta])*
+                $field: $type_
+            ),* ,
+        }
+    }
+}
+
+serializable! {
+    #[allow(dead_code)]
+    /// This is a test
+    pub struct Tester {
+        #[allow(dead_code)]
+        name: String,
+    }
+}
+
+macro_rules! foo_24189_c {
+    ( $( > )* $x:ident ) => { };
+}
+foo_24189_c!( > a );
+
+fn test_24189() {
+    let _ = Foo24189::Baz;
+    let _ = Tester { name: "".to_owned() };
+}
+
+//}}}
+
+//{{{ issue 50903 ==============================================================
+
+macro_rules! foo_50903 {
+    ($($lif:lifetime ,)* #) => {};
+}
+
+foo_50903!('a, 'b, #);
+foo_50903!('a, #);
+foo_50903!(#);
+
+//}}}
+
+//{{{ issue 51477 ==============================================================
+
+macro_rules! foo_51477 {
+    ($lifetime:lifetime) => {
+        "last token is lifetime"
+    };
+    ($other:tt) => {
+        "last token is other"
+    };
+    ($first:tt $($rest:tt)*) => {
+        foo_51477!($($rest)*)
+    };
+}
+
+fn test_51477() {
+    assert_eq!("last token is lifetime", foo_51477!('a));
+    assert_eq!("last token is other", foo_51477!(@));
+    assert_eq!("last token is lifetime", foo_51477!(@ {} 'a));
+}
+
+//}}}
+
+//{{{ some more tests ==========================================================
+
+macro_rules! test_block {
+    (< $($b:block)* >) => {}
+}
+
+test_block!(<>);
+test_block!(<{}>);
+test_block!(<{1}{2}>);
+
+macro_rules! test_ty {
+    ($($t:ty),* $(,)*) => {}
+}
+
+test_ty!();
+test_ty!(,);
+test_ty!(u8);
+test_ty!(u8,);
+
+macro_rules! test_path {
+    ($($t:path),* $(,)*) => {}
+}
+
+test_path!();
+test_path!(,);
+test_path!(::std);
+test_path!(std::ops,);
+test_path!(any, super, super::super::self::path, X<Y>::Z<'a, T=U>);
+
+macro_rules! test_lifetime {
+    (1. $($l:lifetime)* $($b:block)*) => {};
+    (2. $($b:block)* $($l:lifetime)*) => {};
+}
+
+test_lifetime!(1. 'a 'b {} {});
+test_lifetime!(2. {} {} 'a 'b);
+
+//}}}
+
+fn main() {
+    test_26444();
+    test_40569();
+    test_35650();
+    test_24189();
+    test_51477();
+}
diff --git a/tests/ui/macros/macro-follow-rpass.rs b/tests/ui/macros/macro-follow-rpass.rs
new file mode 100644
index 00000000000..ca93655631f
--- /dev/null
+++ b/tests/ui/macros/macro-follow-rpass.rs
@@ -0,0 +1,183 @@
+// run-pass
+#![allow(unused_macros)]
+// Check the macro follow sets (see corresponding cfail test).
+
+// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
+macro_rules! follow_pat {
+    ($p:pat =>) => {};
+    ($p:pat ,) => {};
+    ($p:pat =) => {};
+    ($p:pat |) => {};
+    ($p:pat if) => {};
+    ($p:pat in) => {};
+}
+// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
+macro_rules! follow_expr {
+    ($e:expr =>) => {};
+    ($e:expr ,) => {};
+    ($e:expr ;) => {};
+}
+// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
+//               Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)}
+macro_rules! follow_ty {
+    ($t:ty {}) => {};
+    ($t:ty ,) => {};
+    ($t:ty =>) => {};
+    ($t:ty :) => {};
+    ($t:ty =) => {};
+    ($t:ty >) => {};
+    ($t:ty ;) => {};
+    ($t:ty |) => {};
+    ($t:ty as) => {};
+    ($t:ty where) => {};
+    ($t:ty []) => {};
+    ($t:ty $b:block) => {};
+}
+// FOLLOW(stmt) = FOLLOW(expr)
+macro_rules! follow_stmt {
+    ($s:stmt =>) => {};
+    ($s:stmt ,) => {};
+    ($s:stmt ;) => {};
+}
+// FOLLOW(path) = FOLLOW(ty)
+macro_rules! follow_path {
+    ($p:path {}) => {};
+    ($p:path ,) => {};
+    ($p:path =>) => {};
+    ($p:path :) => {};
+    ($p:path =) => {};
+    ($p:path >) => {};
+    ($p:path ;) => {};
+    ($p:path |) => {};
+    ($p:path as) => {};
+    ($p:path where) => {};
+    ($p:path []) => {};
+    ($p:path $b:block) => {};
+}
+// FOLLOW(block) = any token
+macro_rules! follow_block {
+    ($b:block ()) => {};
+    ($b:block []) => {};
+    ($b:block {}) => {};
+    ($b:block ,) => {};
+    ($b:block =>) => {};
+    ($b:block :) => {};
+    ($b:block =) => {};
+    ($b:block >) => {};
+    ($b:block ;) => {};
+    ($b:block |) => {};
+    ($b:block +) => {};
+    ($b:block ident) => {};
+    ($b:block $p:pat) => {};
+    ($b:block $e:expr) => {};
+    ($b:block $t:ty) => {};
+    ($b:block $s:stmt) => {};
+    ($b:block $p:path) => {};
+    ($b:block $c:block) => {};
+    ($b:block $i:ident) => {};
+    ($b:block $t:tt) => {};
+    ($b:block $i:item) => {};
+    ($b:block $m:meta) => {};
+}
+// FOLLOW(ident) = any token
+macro_rules! follow_ident {
+    ($i:ident ()) => {};
+    ($i:ident []) => {};
+    ($i:ident {}) => {};
+    ($i:ident ,) => {};
+    ($i:ident =>) => {};
+    ($i:ident :) => {};
+    ($i:ident =) => {};
+    ($i:ident >) => {};
+    ($i:ident ;) => {};
+    ($i:ident |) => {};
+    ($i:ident +) => {};
+    ($i:ident ident) => {};
+    ($i:ident $p:pat) => {};
+    ($i:ident $e:expr) => {};
+    ($i:ident $t:ty) => {};
+    ($i:ident $s:stmt) => {};
+    ($i:ident $p:path) => {};
+    ($i:ident $b:block) => {};
+    ($i:ident $j:ident) => {};
+    ($i:ident $t:tt) => {};
+    ($i:ident $j:item) => {};
+    ($i:ident $m:meta) => {};
+}
+// FOLLOW(tt) = any token
+macro_rules! follow_tt {
+    ($t:tt ()) => {};
+    ($t:tt []) => {};
+    ($t:tt {}) => {};
+    ($t:tt ,) => {};
+    ($t:tt =>) => {};
+    ($t:tt :) => {};
+    ($t:tt =) => {};
+    ($t:tt >) => {};
+    ($t:tt ;) => {};
+    ($t:tt |) => {};
+    ($t:tt +) => {};
+    ($t:tt ident) => {};
+    ($t:tt $p:pat) => {};
+    ($t:tt $e:expr) => {};
+    ($t:tt $v:ty) => {};
+    ($t:tt $s:stmt) => {};
+    ($t:tt $p:path) => {};
+    ($t:tt $b:block) => {};
+    ($t:tt $i:ident) => {};
+    ($t:tt $v:tt) => {};
+    ($t:tt $i:item) => {};
+    ($t:tt $m:meta) => {};
+}
+// FOLLOW(item) = any token
+macro_rules! follow_item {
+    ($i:item ()) => {};
+    ($i:item []) => {};
+    ($i:item {}) => {};
+    ($i:item ,) => {};
+    ($i:item =>) => {};
+    ($i:item :) => {};
+    ($i:item =) => {};
+    ($i:item >) => {};
+    ($i:item ;) => {};
+    ($i:item |) => {};
+    ($i:item +) => {};
+    ($i:item ident) => {};
+    ($i:item $p:pat) => {};
+    ($i:item $e:expr) => {};
+    ($i:item $t:ty) => {};
+    ($i:item $s:stmt) => {};
+    ($i:item $p:path) => {};
+    ($i:item $b:block) => {};
+    ($i:item $j:ident) => {};
+    ($i:item $t:tt) => {};
+    ($i:item $j:item) => {};
+    ($i:item $m:meta) => {};
+}
+// FOLLOW(meta) = any token
+macro_rules! follow_meta {
+    ($m:meta ()) => {};
+    ($m:meta []) => {};
+    ($m:meta {}) => {};
+    ($m:meta ,) => {};
+    ($m:meta =>) => {};
+    ($m:meta :) => {};
+    ($m:meta =) => {};
+    ($m:meta >) => {};
+    ($m:meta ;) => {};
+    ($m:meta |) => {};
+    ($m:meta +) => {};
+    ($m:meta ident) => {};
+    ($m:meta $p:pat) => {};
+    ($m:meta $e:expr) => {};
+    ($m:meta $t:ty) => {};
+    ($m:meta $s:stmt) => {};
+    ($m:meta $p:path) => {};
+    ($m:meta $b:block) => {};
+    ($m:meta $i:ident) => {};
+    ($m:meta $t:tt) => {};
+    ($m:meta $i:item) => {};
+    ($m:meta $n:meta) => {};
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-follow.rs b/tests/ui/macros/macro-follow.rs
new file mode 100644
index 00000000000..8054418d9b8
--- /dev/null
+++ b/tests/ui/macros/macro-follow.rs
@@ -0,0 +1,114 @@
+//
+// Check the macro follow sets (see corresponding rpass test).
+
+#![allow(unused_macros)]
+
+// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
+macro_rules! follow_pat {
+    ($p:pat ()) => {};       //~ERROR  `$p:pat` is followed by `(`
+    ($p:pat []) => {};       //~ERROR  `$p:pat` is followed by `[`
+    ($p:pat {}) => {};       //~ERROR  `$p:pat` is followed by `{`
+    ($p:pat :) => {};        //~ERROR `$p:pat` is followed by `:`
+    ($p:pat >) => {};        //~ERROR `$p:pat` is followed by `>`
+    ($p:pat +) => {};        //~ERROR `$p:pat` is followed by `+`
+    ($p:pat ident) => {};    //~ERROR `$p:pat` is followed by `ident`
+    ($p:pat $q:pat) => {};   //~ERROR `$p:pat` is followed by `$q:pat`
+    ($p:pat $e:expr) => {};  //~ERROR `$p:pat` is followed by `$e:expr`
+    ($p:pat $t:ty) => {};    //~ERROR `$p:pat` is followed by `$t:ty`
+    ($p:pat $s:stmt) => {};  //~ERROR `$p:pat` is followed by `$s:stmt`
+    ($p:pat $q:path) => {};  //~ERROR `$p:pat` is followed by `$q:path`
+    ($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block`
+    ($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident`
+    ($p:pat $t:tt) => {};    //~ERROR `$p:pat` is followed by `$t:tt`
+    ($p:pat $i:item) => {};  //~ERROR `$p:pat` is followed by `$i:item`
+    ($p:pat $m:meta) => {};  //~ERROR `$p:pat` is followed by `$m:meta`
+}
+// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
+macro_rules! follow_expr {
+    ($e:expr ()) => {};       //~ERROR  `$e:expr` is followed by `(`
+    ($e:expr []) => {};       //~ERROR  `$e:expr` is followed by `[`
+    ($e:expr {}) => {};       //~ERROR  `$e:expr` is followed by `{`
+    ($e:expr =) => {};        //~ERROR `$e:expr` is followed by `=`
+    ($e:expr |) => {};        //~ERROR `$e:expr` is followed by `|`
+    ($e:expr :) => {};        //~ERROR `$e:expr` is followed by `:`
+    ($e:expr >) => {};        //~ERROR `$e:expr` is followed by `>`
+    ($e:expr +) => {};        //~ERROR `$e:expr` is followed by `+`
+    ($e:expr ident) => {};    //~ERROR `$e:expr` is followed by `ident`
+    ($e:expr if) => {};       //~ERROR `$e:expr` is followed by `if`
+    ($e:expr in) => {};       //~ERROR `$e:expr` is followed by `in`
+    ($e:expr $p:pat) => {};   //~ERROR `$e:expr` is followed by `$p:pat`
+    ($e:expr $f:expr) => {};  //~ERROR `$e:expr` is followed by `$f:expr`
+    ($e:expr $t:ty) => {};    //~ERROR `$e:expr` is followed by `$t:ty`
+    ($e:expr $s:stmt) => {};  //~ERROR `$e:expr` is followed by `$s:stmt`
+    ($e:expr $p:path) => {};  //~ERROR `$e:expr` is followed by `$p:path`
+    ($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block`
+    ($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident`
+    ($e:expr $t:tt) => {};    //~ERROR `$e:expr` is followed by `$t:tt`
+    ($e:expr $i:item) => {};  //~ERROR `$e:expr` is followed by `$i:item`
+    ($e:expr $m:meta) => {};  //~ERROR `$e:expr` is followed by `$m:meta`
+}
+// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
+//               Ident(as), Ident(where), OpenDelim(Bracket), Nonterminal(Block)}
+macro_rules! follow_ty {
+    ($t:ty ()) => {};       //~ERROR  `$t:ty` is followed by `(`
+    ($t:ty []) => {};       // ok (RFC 1462)
+    ($t:ty +) => {};        //~ERROR `$t:ty` is followed by `+`
+    ($t:ty ident) => {};    //~ERROR `$t:ty` is followed by `ident`
+    ($t:ty if) => {};       //~ERROR `$t:ty` is followed by `if`
+    ($t:ty $p:pat) => {};   //~ERROR `$t:ty` is followed by `$p:pat`
+    ($t:ty $e:expr) => {};  //~ERROR `$t:ty` is followed by `$e:expr`
+    ($t:ty $r:ty) => {};    //~ERROR `$t:ty` is followed by `$r:ty`
+    ($t:ty $s:stmt) => {};  //~ERROR `$t:ty` is followed by `$s:stmt`
+    ($t:ty $p:path) => {};  //~ERROR `$t:ty` is followed by `$p:path`
+    ($t:ty $b:block) => {}; // ok (RFC 1494)
+    ($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident`
+    ($t:ty $r:tt) => {};    //~ERROR `$t:ty` is followed by `$r:tt`
+    ($t:ty $i:item) => {};  //~ERROR `$t:ty` is followed by `$i:item`
+    ($t:ty $m:meta) => {};  //~ERROR `$t:ty` is followed by `$m:meta`
+}
+// FOLLOW(stmt) = FOLLOW(expr)
+macro_rules! follow_stmt {
+    ($s:stmt ()) => {};       //~ERROR  `$s:stmt` is followed by `(`
+    ($s:stmt []) => {};       //~ERROR  `$s:stmt` is followed by `[`
+    ($s:stmt {}) => {};       //~ERROR  `$s:stmt` is followed by `{`
+    ($s:stmt =) => {};        //~ERROR `$s:stmt` is followed by `=`
+    ($s:stmt |) => {};        //~ERROR `$s:stmt` is followed by `|`
+    ($s:stmt :) => {};        //~ERROR `$s:stmt` is followed by `:`
+    ($s:stmt >) => {};        //~ERROR `$s:stmt` is followed by `>`
+    ($s:stmt +) => {};        //~ERROR `$s:stmt` is followed by `+`
+    ($s:stmt ident) => {};    //~ERROR `$s:stmt` is followed by `ident`
+    ($s:stmt if) => {};       //~ERROR `$s:stmt` is followed by `if`
+    ($s:stmt in) => {};       //~ERROR `$s:stmt` is followed by `in`
+    ($s:stmt $p:pat) => {};   //~ERROR `$s:stmt` is followed by `$p:pat`
+    ($s:stmt $e:expr) => {};  //~ERROR `$s:stmt` is followed by `$e:expr`
+    ($s:stmt $t:ty) => {};    //~ERROR `$s:stmt` is followed by `$t:ty`
+    ($s:stmt $t:stmt) => {};  //~ERROR `$s:stmt` is followed by `$t:stmt`
+    ($s:stmt $p:path) => {};  //~ERROR `$s:stmt` is followed by `$p:path`
+    ($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block`
+    ($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident`
+    ($s:stmt $t:tt) => {};    //~ERROR `$s:stmt` is followed by `$t:tt`
+    ($s:stmt $i:item) => {};  //~ERROR `$s:stmt` is followed by `$i:item`
+    ($s:stmt $m:meta) => {};  //~ERROR `$s:stmt` is followed by `$m:meta`
+}
+// FOLLOW(path) = FOLLOW(ty)
+macro_rules! follow_path {
+    ($p:path ()) => {};       //~ERROR  `$p:path` is followed by `(`
+    ($p:path []) => {};       // ok (RFC 1462)
+    ($p:path +) => {};        //~ERROR `$p:path` is followed by `+`
+    ($p:path ident) => {};    //~ERROR `$p:path` is followed by `ident`
+    ($p:path if) => {};       //~ERROR `$p:path` is followed by `if`
+    ($p:path $q:pat) => {};   //~ERROR `$p:path` is followed by `$q:pat`
+    ($p:path $e:expr) => {};  //~ERROR `$p:path` is followed by `$e:expr`
+    ($p:path $t:ty) => {};    //~ERROR `$p:path` is followed by `$t:ty`
+    ($p:path $s:stmt) => {};  //~ERROR `$p:path` is followed by `$s:stmt`
+    ($p:path $q:path) => {};  //~ERROR `$p:path` is followed by `$q:path`
+    ($p:path $b:block) => {}; // ok (RFC 1494)
+    ($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident`
+    ($p:path $t:tt) => {};    //~ERROR `$p:path` is followed by `$t:tt`
+    ($p:path $i:item) => {};  //~ERROR `$p:path` is followed by `$i:item`
+    ($p:path $m:meta) => {};  //~ERROR `$p:path` is followed by `$m:meta`
+}
+// FOLLOW(block) = any token
+// FOLLOW(ident) = any token
+
+fn main() {}
diff --git a/tests/ui/macros/macro-follow.stderr b/tests/ui/macros/macro-follow.stderr
new file mode 100644
index 00000000000..61ae79d235e
--- /dev/null
+++ b/tests/ui/macros/macro-follow.stderr
@@ -0,0 +1,682 @@
+error: `$p:pat` is followed by `(`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:8:13
+   |
+LL |     ($p:pat ()) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `[`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:9:13
+   |
+LL |     ($p:pat []) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `{`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:10:13
+   |
+LL |     ($p:pat {}) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `:`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:11:13
+   |
+LL |     ($p:pat :) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `>`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:12:13
+   |
+LL |     ($p:pat >) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `+`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:13:13
+   |
+LL |     ($p:pat +) => {};
+   |             ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `ident`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:14:13
+   |
+LL |     ($p:pat ident) => {};
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$q:pat`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:15:13
+   |
+LL |     ($p:pat $q:pat) => {};
+   |             ^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$e:expr`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:16:13
+   |
+LL |     ($p:pat $e:expr) => {};
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$t:ty`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:17:13
+   |
+LL |     ($p:pat $t:ty) => {};
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$s:stmt`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:18:13
+   |
+LL |     ($p:pat $s:stmt) => {};
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$q:path`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:19:13
+   |
+LL |     ($p:pat $q:path) => {};
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$b:block`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:20:13
+   |
+LL |     ($p:pat $b:block) => {};
+   |             ^^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$i:ident`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:21:13
+   |
+LL |     ($p:pat $i:ident) => {};
+   |             ^^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$t:tt`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:22:13
+   |
+LL |     ($p:pat $t:tt) => {};
+   |             ^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$i:item`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:23:13
+   |
+LL |     ($p:pat $i:item) => {};
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$p:pat` is followed by `$m:meta`, which is not allowed for `pat` fragments
+  --> $DIR/macro-follow.rs:24:13
+   |
+LL |     ($p:pat $m:meta) => {};
+   |             ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$e:expr` is followed by `(`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:28:14
+   |
+LL |     ($e:expr ()) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `[`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:29:14
+   |
+LL |     ($e:expr []) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `{`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:30:14
+   |
+LL |     ($e:expr {}) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `=`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:31:14
+   |
+LL |     ($e:expr =) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `|`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:32:14
+   |
+LL |     ($e:expr |) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `:`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:33:14
+   |
+LL |     ($e:expr :) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `>`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:34:14
+   |
+LL |     ($e:expr >) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `+`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:35:14
+   |
+LL |     ($e:expr +) => {};
+   |              ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `ident`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:36:14
+   |
+LL |     ($e:expr ident) => {};
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `if`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:37:14
+   |
+LL |     ($e:expr if) => {};
+   |              ^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `in`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:38:14
+   |
+LL |     ($e:expr in) => {};
+   |              ^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$p:pat`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:39:14
+   |
+LL |     ($e:expr $p:pat) => {};
+   |              ^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$f:expr`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:40:14
+   |
+LL |     ($e:expr $f:expr) => {};
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$t:ty`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:41:14
+   |
+LL |     ($e:expr $t:ty) => {};
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$s:stmt`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:42:14
+   |
+LL |     ($e:expr $s:stmt) => {};
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$p:path`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:43:14
+   |
+LL |     ($e:expr $p:path) => {};
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$b:block`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:44:14
+   |
+LL |     ($e:expr $b:block) => {};
+   |              ^^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$i:ident`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:45:14
+   |
+LL |     ($e:expr $i:ident) => {};
+   |              ^^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$t:tt`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:46:14
+   |
+LL |     ($e:expr $t:tt) => {};
+   |              ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$i:item`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:47:14
+   |
+LL |     ($e:expr $i:item) => {};
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$e:expr` is followed by `$m:meta`, which is not allowed for `expr` fragments
+  --> $DIR/macro-follow.rs:48:14
+   |
+LL |     ($e:expr $m:meta) => {};
+   |              ^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$t:ty` is followed by `(`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:53:12
+   |
+LL |     ($t:ty ()) => {};
+   |            ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `+`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:55:12
+   |
+LL |     ($t:ty +) => {};
+   |            ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `ident`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:56:12
+   |
+LL |     ($t:ty ident) => {};
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `if`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:57:12
+   |
+LL |     ($t:ty if) => {};
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$p:pat`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:58:12
+   |
+LL |     ($t:ty $p:pat) => {};
+   |            ^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$e:expr`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:59:12
+   |
+LL |     ($t:ty $e:expr) => {};
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$r:ty`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:60:12
+   |
+LL |     ($t:ty $r:ty) => {};
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$s:stmt`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:61:12
+   |
+LL |     ($t:ty $s:stmt) => {};
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$p:path`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:62:12
+   |
+LL |     ($t:ty $p:path) => {};
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$i:ident`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:64:12
+   |
+LL |     ($t:ty $i:ident) => {};
+   |            ^^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$r:tt`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:65:12
+   |
+LL |     ($t:ty $r:tt) => {};
+   |            ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$i:item`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:66:12
+   |
+LL |     ($t:ty $i:item) => {};
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$t:ty` is followed by `$m:meta`, which is not allowed for `ty` fragments
+  --> $DIR/macro-follow.rs:67:12
+   |
+LL |     ($t:ty $m:meta) => {};
+   |            ^^^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$s:stmt` is followed by `(`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:71:14
+   |
+LL |     ($s:stmt ()) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `[`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:72:14
+   |
+LL |     ($s:stmt []) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `{`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:73:14
+   |
+LL |     ($s:stmt {}) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `=`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:74:14
+   |
+LL |     ($s:stmt =) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `|`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:75:14
+   |
+LL |     ($s:stmt |) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `:`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:76:14
+   |
+LL |     ($s:stmt :) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `>`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:77:14
+   |
+LL |     ($s:stmt >) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `+`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:78:14
+   |
+LL |     ($s:stmt +) => {};
+   |              ^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `ident`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:79:14
+   |
+LL |     ($s:stmt ident) => {};
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `if`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:80:14
+   |
+LL |     ($s:stmt if) => {};
+   |              ^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `in`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:81:14
+   |
+LL |     ($s:stmt in) => {};
+   |              ^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$p:pat`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:82:14
+   |
+LL |     ($s:stmt $p:pat) => {};
+   |              ^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$e:expr`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:83:14
+   |
+LL |     ($s:stmt $e:expr) => {};
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$t:ty`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:84:14
+   |
+LL |     ($s:stmt $t:ty) => {};
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$t:stmt`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:85:14
+   |
+LL |     ($s:stmt $t:stmt) => {};
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$p:path`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:86:14
+   |
+LL |     ($s:stmt $p:path) => {};
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$b:block`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:87:14
+   |
+LL |     ($s:stmt $b:block) => {};
+   |              ^^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$i:ident`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:88:14
+   |
+LL |     ($s:stmt $i:ident) => {};
+   |              ^^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$t:tt`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:89:14
+   |
+LL |     ($s:stmt $t:tt) => {};
+   |              ^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$i:item`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:90:14
+   |
+LL |     ($s:stmt $i:item) => {};
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$s:stmt` is followed by `$m:meta`, which is not allowed for `stmt` fragments
+  --> $DIR/macro-follow.rs:91:14
+   |
+LL |     ($s:stmt $m:meta) => {};
+   |              ^^^^^^^ not allowed after `stmt` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$p:path` is followed by `(`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:95:14
+   |
+LL |     ($p:path ()) => {};
+   |              ^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `+`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:97:14
+   |
+LL |     ($p:path +) => {};
+   |              ^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `ident`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:98:14
+   |
+LL |     ($p:path ident) => {};
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `if`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:99:14
+   |
+LL |     ($p:path if) => {};
+   |              ^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$q:pat`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:100:14
+   |
+LL |     ($p:path $q:pat) => {};
+   |              ^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$e:expr`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:101:14
+   |
+LL |     ($p:path $e:expr) => {};
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$t:ty`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:102:14
+   |
+LL |     ($p:path $t:ty) => {};
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$s:stmt`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:103:14
+   |
+LL |     ($p:path $s:stmt) => {};
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$q:path`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:104:14
+   |
+LL |     ($p:path $q:path) => {};
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$i:ident`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:106:14
+   |
+LL |     ($p:path $i:ident) => {};
+   |              ^^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$t:tt`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:107:14
+   |
+LL |     ($p:path $t:tt) => {};
+   |              ^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$i:item`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:108:14
+   |
+LL |     ($p:path $i:item) => {};
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$p:path` is followed by `$m:meta`, which is not allowed for `path` fragments
+  --> $DIR/macro-follow.rs:109:14
+   |
+LL |     ($p:path $m:meta) => {};
+   |              ^^^^^^^ not allowed after `path` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 85 previous errors
+
diff --git a/tests/ui/macros/macro-followed-by-seq-bad.rs b/tests/ui/macros/macro-followed-by-seq-bad.rs
new file mode 100644
index 00000000000..b73742f77ea
--- /dev/null
+++ b/tests/ui/macros/macro-followed-by-seq-bad.rs
@@ -0,0 +1,11 @@
+// Regression test for issue #25436: check that things which can be
+// followed by any token also permit X* to come afterwards.
+
+#![allow(unused_macros)]
+
+macro_rules! foo {
+  ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments
+  ( $a:ty $($b:tt)* ) => { };   //~ ERROR not allowed for `ty` fragments
+}
+
+fn main() { }
diff --git a/tests/ui/macros/macro-followed-by-seq-bad.stderr b/tests/ui/macros/macro-followed-by-seq-bad.stderr
new file mode 100644
index 00000000000..7097979aedd
--- /dev/null
+++ b/tests/ui/macros/macro-followed-by-seq-bad.stderr
@@ -0,0 +1,18 @@
+error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
+  --> $DIR/macro-followed-by-seq-bad.rs:7:15
+   |
+LL |   ( $a:expr $($b:tt)* ) => { };
+   |               ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$a:ty` is followed by `$b:tt`, which is not allowed for `ty` fragments
+  --> $DIR/macro-followed-by-seq-bad.rs:8:13
+   |
+LL |   ( $a:ty $($b:tt)* ) => { };
+   |             ^^^^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-followed-by-seq.rs b/tests/ui/macros/macro-followed-by-seq.rs
new file mode 100644
index 00000000000..71d59d8d31b
--- /dev/null
+++ b/tests/ui/macros/macro-followed-by-seq.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(unused_macros)]
+// Regression test for issue #25436: check that things which can be
+// followed by any token also permit X* to come afterwards.
+
+macro_rules! foo {
+  ( $a:tt $($b:tt)* ) => { };
+  ( $a:ident $($b:tt)* ) => { };
+  ( $a:item $($b:tt)* ) => { };
+  ( $a:block $($b:tt)* ) => { };
+  ( $a:meta $($b:tt)* ) => { }
+}
+
+fn main() { }
diff --git a/tests/ui/macros/macro-in-expression-context-2.rs b/tests/ui/macros/macro-in-expression-context-2.rs
new file mode 100644
index 00000000000..9423f0a359c
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context-2.rs
@@ -0,0 +1,8 @@
+macro_rules! empty { () => () }
+
+fn main() {
+    match 42 {
+        _ => { empty!() }
+//~^ ERROR macro expansion ends with an incomplete expression
+    };
+}
diff --git a/tests/ui/macros/macro-in-expression-context-2.stderr b/tests/ui/macros/macro-in-expression-context-2.stderr
new file mode 100644
index 00000000000..d0312c48508
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context-2.stderr
@@ -0,0 +1,17 @@
+error: macro expansion ends with an incomplete expression: expected expression
+  --> $DIR/macro-in-expression-context-2.rs:5:16
+   |
+LL | macro_rules! empty { () => () }
+   |                            -- in this macro arm
+...
+LL |         _ => { empty!() }
+   |                ^^^^^^^^ expected expression
+   |
+   = note: the macro call doesn't expand to an expression, but it can expand to a statement
+help: add `;` to interpret the expansion as a statement
+   |
+LL |         _ => { empty!(); }
+   |                        +
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed
new file mode 100644
index 00000000000..f22caf2793f
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+
+macro_rules! foo {
+    () => {
+        assert_eq!("A", "A");
+        //~^ WARN trailing semicolon in macro
+        //~| WARN this was previously
+        //~| NOTE macro invocations at the end of a block
+        //~| NOTE to ignore the value produced by the macro
+        //~| NOTE for more information
+        //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
+        assert_eq!("B", "B");
+    }
+    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+    foo!();
+    //~^ NOTE caused by the macro expansion here
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+}
diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs
new file mode 100644
index 00000000000..1a056e582ff
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+
+macro_rules! foo {
+    () => {
+        assert_eq!("A", "A");
+        //~^ WARN trailing semicolon in macro
+        //~| WARN this was previously
+        //~| NOTE macro invocations at the end of a block
+        //~| NOTE to ignore the value produced by the macro
+        //~| NOTE for more information
+        //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
+        assert_eq!("B", "B");
+    }
+    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~| NOTE the usage of `foo!` is likely invalid in expression context
+}
+
+fn main() {
+    foo!()
+    //~^ NOTE caused by the macro expansion here
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+    //~| NOTE in this expansion
+}
diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr
new file mode 100644
index 00000000000..36aba8aa08a
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context.stderr
@@ -0,0 +1,33 @@
+error: macro expansion ignores token `assert_eq` and any following
+  --> $DIR/macro-in-expression-context.rs:12:9
+   |
+LL |         assert_eq!("B", "B");
+   |         ^^^^^^^^^
+...
+LL |     foo!()
+   |     ------ caused by the macro expansion here
+   |
+   = note: the usage of `foo!` is likely invalid in expression context
+help: you might be missing a semicolon here
+   |
+LL |     foo!();
+   |           +
+
+warning: trailing semicolon in macro used in expression position
+  --> $DIR/macro-in-expression-context.rs:5:29
+   |
+LL |         assert_eq!("A", "A");
+   |                             ^
+...
+LL |     foo!()
+   |     ------ in this macro invocation
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
+   = note: macro invocations at the end of a block are treated as expressions
+   = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
+   = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default
+   = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/ui/macros/macro-in-fn.rs b/tests/ui/macros/macro-in-fn.rs
new file mode 100644
index 00000000000..d354fe4a7db
--- /dev/null
+++ b/tests/ui/macros/macro-in-fn.rs
@@ -0,0 +1,8 @@
+// run-pass
+#![feature(decl_macro)]
+
+pub fn moo() {
+    pub macro ABC() {{}}
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-include-items.rs b/tests/ui/macros/macro-include-items.rs
new file mode 100644
index 00000000000..332bf59c944
--- /dev/null
+++ b/tests/ui/macros/macro-include-items.rs
@@ -0,0 +1,13 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+// ignore-pretty issue #37195
+
+fn bar() {}
+
+include!(concat!("", "", "auxiliary/", "macro-include-items-item.rs"));
+
+fn main() {
+    foo();
+    assert_eq!(include!(concat!("", "auxiliary/", "macro-include-items-expr.rs")), 1_usize);
+}
diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs
new file mode 100644
index 00000000000..a8cda23075b
--- /dev/null
+++ b/tests/ui/macros/macro-inner-attributes.rs
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs)]
+
+macro_rules! test { ($nm:ident,
+                     #[$a:meta],
+                     $i:item) => (mod $nm { #![$a] $i }); }
+
+test!(a,
+      #[cfg(qux)],
+      pub fn bar() { });
+
+test!(b,
+      #[cfg(not(qux))],
+      pub fn bar() { });
+
+#[rustc_dummy]
+fn main() {
+    a::bar();
+    //~^ ERROR failed to resolve: use of undeclared crate or module `a`
+    b::bar();
+}
diff --git a/tests/ui/macros/macro-inner-attributes.stderr b/tests/ui/macros/macro-inner-attributes.stderr
new file mode 100644
index 00000000000..77b6486155c
--- /dev/null
+++ b/tests/ui/macros/macro-inner-attributes.stderr
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `a`
+  --> $DIR/macro-inner-attributes.rs:17:5
+   |
+LL |     a::bar();
+   |     ^ use of undeclared crate or module `a`
+   |
+help: there is a crate or module with a similar name
+   |
+LL |     b::bar();
+   |     ~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/macro-input-future-proofing.rs b/tests/ui/macros/macro-input-future-proofing.rs
new file mode 100644
index 00000000000..9a5bdb08a8e
--- /dev/null
+++ b/tests/ui/macros/macro-input-future-proofing.rs
@@ -0,0 +1,23 @@
+#![allow(unused_macros)]
+
+macro_rules! errors_everywhere {
+    ($ty:ty <) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
+    ($ty:ty < foo ,) => (); //~ ERROR `$ty:ty` is followed by `<`, which is not allowed for `ty`
+    ($ty:ty , ) => ();
+    ( ( $ty:ty ) ) => ();
+    ( { $ty:ty } ) => ();
+    ( [ $ty:ty ] ) => ();
+    ($bl:block < ) => ();
+    ($pa:pat >) => (); //~ ERROR `$pa:pat` is followed by `>`, which is not allowed for `pat`
+    ($pa:pat , ) => ();
+    ($pa:pat $pb:pat $ty:ty ,) => ();
+    //~^ ERROR `$pa:pat` is followed by `$pb:pat`, which is not allowed
+    //~^^ ERROR `$pb:pat` is followed by `$ty:ty`, which is not allowed
+    ($($ty:ty)* -) => (); //~ ERROR `$ty:ty` is followed by `-`
+    ($($a:ty, $b:ty)* -) => (); //~ ERROR `$b:ty` is followed by `-`
+    ($($ty:ty)-+) => (); //~ ERROR `$ty:ty` is followed by `-`, which is not allowed for `ty`
+    ( $($a:expr)* $($b:tt)* ) => { };
+    //~^ ERROR `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
+}
+
+fn main() { }
diff --git a/tests/ui/macros/macro-input-future-proofing.stderr b/tests/ui/macros/macro-input-future-proofing.stderr
new file mode 100644
index 00000000000..542486927df
--- /dev/null
+++ b/tests/ui/macros/macro-input-future-proofing.stderr
@@ -0,0 +1,74 @@
+error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments
+  --> $DIR/macro-input-future-proofing.rs:4:13
+   |
+LL |     ($ty:ty <) => ();
+   |             ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$ty:ty` is followed by `<`, which is not allowed for `ty` fragments
+  --> $DIR/macro-input-future-proofing.rs:5:13
+   |
+LL |     ($ty:ty < foo ,) => ();
+   |             ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$pa:pat` is followed by `>`, which is not allowed for `pat` fragments
+  --> $DIR/macro-input-future-proofing.rs:11:14
+   |
+LL |     ($pa:pat >) => ();
+   |              ^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$pa:pat` is followed by `$pb:pat`, which is not allowed for `pat` fragments
+  --> $DIR/macro-input-future-proofing.rs:13:14
+   |
+LL |     ($pa:pat $pb:pat $ty:ty ,) => ();
+   |              ^^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$pb:pat` is followed by `$ty:ty`, which is not allowed for `pat` fragments
+  --> $DIR/macro-input-future-proofing.rs:13:22
+   |
+LL |     ($pa:pat $pb:pat $ty:ty ,) => ();
+   |                      ^^^^^^ not allowed after `pat` fragments
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `|`, `if` or `in`
+
+error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
+  --> $DIR/macro-input-future-proofing.rs:16:17
+   |
+LL |     ($($ty:ty)* -) => ();
+   |                 ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$b:ty` is followed by `-`, which is not allowed for `ty` fragments
+  --> $DIR/macro-input-future-proofing.rs:17:23
+   |
+LL |     ($($a:ty, $b:ty)* -) => ();
+   |                       ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$ty:ty` is followed by `-`, which is not allowed for `ty` fragments
+  --> $DIR/macro-input-future-proofing.rs:18:15
+   |
+LL |     ($($ty:ty)-+) => ();
+   |               ^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
+  --> $DIR/macro-input-future-proofing.rs:19:21
+   |
+LL |     ( $($a:expr)* $($b:tt)* ) => { };
+   |                     ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/macros/macro-interpolation.rs b/tests/ui/macros/macro-interpolation.rs
new file mode 100644
index 00000000000..35003a79ad7
--- /dev/null
+++ b/tests/ui/macros/macro-interpolation.rs
@@ -0,0 +1,33 @@
+// run-pass
+
+macro_rules! overly_complicated {
+    ($fnname:ident, $arg:ident, $ty:ty, $body:block, $val:expr, $pat:pat, $res:path) =>
+    ({
+        fn $fnname($arg: $ty) -> Option<$ty> $body
+        match $fnname($val) {
+          Some($pat) => {
+            $res
+          }
+          _ => { panic!(); }
+        }
+    })
+
+}
+
+macro_rules! qpath {
+    (path, <$type:ty as $trait:path>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+
+    (ty, <$type:ty as $trait:ty>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+}
+
+pub fn main() {
+    let _: qpath!(path, <str as ToOwned>::Owned);
+    let _: qpath!(ty, <str as ToOwned>::Owned);
+
+    assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
+                               Some(8), Some(y), y) == 8)
+}
diff --git a/tests/ui/macros/macro-invalid-fragment-spec.rs b/tests/ui/macros/macro-invalid-fragment-spec.rs
new file mode 100644
index 00000000000..dc4d75096af
--- /dev/null
+++ b/tests/ui/macros/macro-invalid-fragment-spec.rs
@@ -0,0 +1,8 @@
+macro_rules! foo(
+    ($x:foo) => ()
+    //~^ ERROR invalid fragment specifier
+);
+
+fn main() {
+    foo!(foo);
+}
diff --git a/tests/ui/macros/macro-invalid-fragment-spec.stderr b/tests/ui/macros/macro-invalid-fragment-spec.stderr
new file mode 100644
index 00000000000..b0473448265
--- /dev/null
+++ b/tests/ui/macros/macro-invalid-fragment-spec.stderr
@@ -0,0 +1,10 @@
+error: invalid fragment specifier `foo`
+  --> $DIR/macro-invalid-fragment-spec.rs:2:6
+   |
+LL |     ($x:foo) => ()
+   |      ^^^^^^
+   |
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs
new file mode 100644
index 00000000000..8f9dcb94794
--- /dev/null
+++ b/tests/ui/macros/macro-invocation-in-count-expr-fixed-array-type.rs
@@ -0,0 +1,10 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+macro_rules! four {
+    () => (4)
+}
+
+fn main() {
+    let _x: [u16; four!()];
+}
diff --git a/tests/ui/macros/macro-lifetime-used-with-bound.rs b/tests/ui/macros/macro-lifetime-used-with-bound.rs
new file mode 100644
index 00000000000..ea3f74c9ada
--- /dev/null
+++ b/tests/ui/macros/macro-lifetime-used-with-bound.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![allow(unused_variables)]
+macro_rules! foo {
+    ($l:lifetime, $l2:lifetime) => {
+        fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str {
+            arg
+        }
+    }
+}
+
+pub fn main() {
+    foo!('a, 'b);
+    let x: &'static str = f("hi", "there");
+    assert_eq!("hi", x);
+}
diff --git a/tests/ui/macros/macro-lifetime-used-with-labels.rs b/tests/ui/macros/macro-lifetime-used-with-labels.rs
new file mode 100644
index 00000000000..59017da3b69
--- /dev/null
+++ b/tests/ui/macros/macro-lifetime-used-with-labels.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![allow(stable_features)]
+#![allow(unused_labels)]
+#![allow(unreachable_code)]
+
+macro_rules! x {
+    ($a:lifetime) => {
+        $a: loop {
+            break $a;
+            panic!("failed");
+        }
+    }
+}
+macro_rules! br {
+    ($a:lifetime) => {
+        break $a;
+    }
+}
+macro_rules! br2 {
+    ($b:lifetime) => {
+        'b: loop {
+            break $b; // this $b should refer to the outer loop.
+        }
+    }
+}
+fn main() {
+    x!('a);
+    'c: loop {
+        br!('c);
+        panic!("failed");
+    }
+    'b: loop {
+        br2!('b);
+        panic!("failed");
+    }
+}
diff --git a/tests/ui/macros/macro-lifetime-used-with-static.rs b/tests/ui/macros/macro-lifetime-used-with-static.rs
new file mode 100644
index 00000000000..8552c4b8163
--- /dev/null
+++ b/tests/ui/macros/macro-lifetime-used-with-static.rs
@@ -0,0 +1,14 @@
+// run-pass
+macro_rules! foo {
+    ($l:lifetime) => {
+        fn f(arg: &$l str) -> &$l str {
+            arg
+        }
+    }
+}
+
+pub fn main() {
+    foo!('static);
+    let x: &'static str = f("hi");
+    assert_eq!("hi", x);
+}
diff --git a/tests/ui/macros/macro-lifetime.rs b/tests/ui/macros/macro-lifetime.rs
new file mode 100644
index 00000000000..5931fe00907
--- /dev/null
+++ b/tests/ui/macros/macro-lifetime.rs
@@ -0,0 +1,14 @@
+// run-pass
+macro_rules! foo {
+    ($l:lifetime) => {
+        fn f<$l>(arg: &$l str) -> &$l str {
+            arg
+        }
+    }
+}
+
+pub fn main() {
+    foo!('a);
+    let x: &'static str = f("hi");
+    assert_eq!("hi", x);
+}
diff --git a/tests/ui/macros/macro-literal.rs b/tests/ui/macros/macro-literal.rs
new file mode 100644
index 00000000000..3c2e71f9c43
--- /dev/null
+++ b/tests/ui/macros/macro-literal.rs
@@ -0,0 +1,134 @@
+// run-pass
+
+macro_rules! mtester {
+    ($l:literal) => {
+        &format!("macro caught literal: {}", $l)
+    };
+    ($e:expr) => {
+        &format!("macro caught expr: {}", $e)
+    };
+}
+
+macro_rules! two_negative_literals {
+    ($l1:literal $l2:literal) => {
+        &format!("macro caught literals: {}, {}", $l1, $l2)
+    };
+}
+
+macro_rules! only_expr {
+    ($e:expr) => {
+        &format!("macro caught expr: {}", $e)
+    };
+}
+
+#[allow(unused_macro_rules)]
+macro_rules! mtester_dbg {
+    ($l:literal) => {
+        &format!("macro caught literal: {:?}", $l)
+    };
+    ($e:expr) => {
+        &format!("macro caught expr: {:?}", $e)
+    };
+}
+
+macro_rules! catch_range {
+    ($s:literal ..= $e:literal) => {
+        &format!("macro caught literal: {} ..= {}", $s, $e)
+    };
+    (($s:expr) ..= ($e:expr)) => { // Must use ')' before '..='
+        &format!("macro caught expr: {} ..= {}", $s, $e)
+    };
+}
+
+macro_rules! pat_match {
+    ($s:literal ..= $e:literal) => {
+        match 3 {
+            $s ..= $e => "literal, in range",
+            _ => "literal, other",
+        }
+    };
+    ($s:pat) => {
+        match 3 {
+            $s => "pat, single",
+            _ => "pat, other",
+        }
+    };
+}
+
+macro_rules! match_attr {
+    (#[$attr:meta] $e:literal) => {
+        "attr matched literal"
+    };
+    (#[$attr:meta] $e:expr) => {
+        "attr matched expr"
+    };
+}
+
+macro_rules! match_produced_attr {
+    ($lit: literal) => {
+        // Struct with doc comment passed via $literal
+        #[doc = $lit]
+        struct LiteralProduced;
+    };
+    ($expr: expr) => {
+        struct ExprProduced;
+    };
+}
+
+macro_rules! test_user {
+    ($s:literal, $e:literal) => {
+        {
+            let mut v = Vec::new();
+            for i in $s .. $e {
+                v.push(i);
+            }
+            "literal"
+        }
+    };
+    ($s:expr, $e: expr) => {
+        {
+            let mut v = Vec::new();
+            for i in $s .. $e {
+                v.push(i);
+            }
+            "expr"
+        }
+    };
+}
+
+pub fn main() {
+    // Cases where 'literal' catches
+    assert_eq!(mtester!("str"), "macro caught literal: str");
+    assert_eq!(mtester!(2), "macro caught literal: 2");
+    assert_eq!(mtester!(2.2), "macro caught literal: 2.2");
+    assert_eq!(mtester!(1u32), "macro caught literal: 1");
+    assert_eq!(mtester!(0x32), "macro caught literal: 50");
+    assert_eq!(mtester!('c'), "macro caught literal: c");
+    assert_eq!(mtester!(-1.2), "macro caught literal: -1.2");
+    assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3");
+    assert_eq!(catch_range!(2 ..= 3), "macro caught literal: 2 ..= 3");
+    assert_eq!(match_attr!(#[attr] 1), "attr matched literal");
+    assert_eq!(test_user!(10, 20), "literal");
+    assert_eq!(mtester!(false), "macro caught literal: false");
+    assert_eq!(mtester!(true), "macro caught literal: true");
+    match_produced_attr!("a");
+    let _a = LiteralProduced;
+    assert_eq!(pat_match!(1 ..= 3), "literal, in range");
+    assert_eq!(pat_match!(4 ..= 6), "literal, other");
+
+    // Cases where 'expr' catches
+    assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2");
+    assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2");
+    assert_eq!(mtester!((1 + 3)), "macro caught expr: 4");
+    assert_eq!(mtester_dbg!(()), "macro caught expr: ()");
+    assert_eq!(catch_range!((1 + 1) ..= (2 + 2)), "macro caught expr: 2 ..= 4");
+    assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr");
+    assert_eq!(test_user!(10, (20 + 2)), "expr");
+
+    match_produced_attr!((3 + 2));
+    let _b = ExprProduced;
+
+    // Cases where 'pat' matched
+    assert_eq!(pat_match!(3), "pat, single");
+    assert_eq!(pat_match!(6), "pat, other");
+}
diff --git a/tests/ui/macros/macro-local-data-key-priv.rs b/tests/ui/macros/macro-local-data-key-priv.rs
new file mode 100644
index 00000000000..2e4f88f9aa9
--- /dev/null
+++ b/tests/ui/macros/macro-local-data-key-priv.rs
@@ -0,0 +1,10 @@
+// check that the local data keys are private by default.
+
+mod bar {
+    thread_local!(static baz: f64 = 0.0);
+}
+
+fn main() {
+    bar::baz.with(|_| ());
+    //~^ ERROR `baz` is private
+}
diff --git a/tests/ui/macros/macro-local-data-key-priv.stderr b/tests/ui/macros/macro-local-data-key-priv.stderr
new file mode 100644
index 00000000000..fb8cab2794b
--- /dev/null
+++ b/tests/ui/macros/macro-local-data-key-priv.stderr
@@ -0,0 +1,16 @@
+error[E0603]: constant `baz` is private
+  --> $DIR/macro-local-data-key-priv.rs:8:10
+   |
+LL |     bar::baz.with(|_| ());
+   |          ^^^ private constant
+   |
+note: the constant `baz` is defined here
+  --> $DIR/macro-local-data-key-priv.rs:4:5
+   |
+LL |     thread_local!(static baz: f64 = 0.0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `$crate::__thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs
new file mode 100644
index 00000000000..5d9eb55fee0
--- /dev/null
+++ b/tests/ui/macros/macro-match-nonterminal.rs
@@ -0,0 +1,14 @@
+macro_rules! test {
+    ($a, $b) => {
+        //~^ ERROR missing fragment
+        //~| ERROR missing fragment
+        //~| ERROR missing fragment
+        //~| WARN this was previously accepted
+        //~| WARN this was previously accepted
+        ()
+    };
+}
+
+fn main() {
+    test!()
+}
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr
new file mode 100644
index 00000000000..ef7261c0239
--- /dev/null
+++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -0,0 +1,27 @@
+error: missing fragment specifier
+  --> $DIR/macro-match-nonterminal.rs:2:8
+   |
+LL |     ($a, $b) => {
+   |        ^
+
+error: missing fragment specifier
+  --> $DIR/macro-match-nonterminal.rs:2:8
+   |
+LL |     ($a, $b) => {
+   |        ^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+error: missing fragment specifier
+  --> $DIR/macro-match-nonterminal.rs:2:10
+   |
+LL |     ($a, $b) => {
+   |          ^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/macro-meta-items-modern.rs b/tests/ui/macros/macro-meta-items-modern.rs
new file mode 100644
index 00000000000..bc6938d4a6c
--- /dev/null
+++ b/tests/ui/macros/macro-meta-items-modern.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+macro_rules! check { ($meta:meta) => () }
+
+check!(meta(a b c d));
+check!(meta[a b c d]);
+check!(meta { a b c d });
+check!(meta);
+check!(meta = 0);
+
+fn main() {}
diff --git a/tests/ui/macros/macro-meta-items.rs b/tests/ui/macros/macro-meta-items.rs
new file mode 100644
index 00000000000..4cbc252aebf
--- /dev/null
+++ b/tests/ui/macros/macro-meta-items.rs
@@ -0,0 +1,31 @@
+// run-pass
+#![allow(dead_code)]
+// compile-flags: --cfg foo
+
+macro_rules! compiles_fine {
+    ($at:meta) => {
+        #[cfg($at)]
+        static MISTYPED: () = "foo";
+    }
+}
+macro_rules! emit {
+    ($at:meta) => {
+        #[cfg($at)]
+        static MISTYPED: &'static str = "foo";
+    }
+}
+
+// item
+compiles_fine!(bar);
+emit!(foo);
+
+fn foo() {
+    println!("{}", MISTYPED);
+}
+
+pub fn main() {
+    // statement
+    compiles_fine!(baz);
+    emit!(baz);
+    println!("{}", MISTYPED);
+}
diff --git a/tests/ui/macros/macro-method-issue-4621.rs b/tests/ui/macros/macro-method-issue-4621.rs
new file mode 100644
index 00000000000..342fad5f62e
--- /dev/null
+++ b/tests/ui/macros/macro-method-issue-4621.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+struct A;
+
+macro_rules! make_thirteen_method {() => (fn thirteen(&self)->isize {13})}
+impl A { make_thirteen_method!(); }
+
+fn main() {
+    assert_eq!(A.thirteen(),13);
+}
diff --git a/tests/ui/macros/macro-missing-delimiters.rs b/tests/ui/macros/macro-missing-delimiters.rs
new file mode 100644
index 00000000000..290d7615e60
--- /dev/null
+++ b/tests/ui/macros/macro-missing-delimiters.rs
@@ -0,0 +1,7 @@
+macro_rules! baz(
+    baz => () //~ ERROR invalid macro matcher;
+);
+
+fn main() {
+    baz!(baz);
+}
diff --git a/tests/ui/macros/macro-missing-delimiters.stderr b/tests/ui/macros/macro-missing-delimiters.stderr
new file mode 100644
index 00000000000..e7c37c8ddbe
--- /dev/null
+++ b/tests/ui/macros/macro-missing-delimiters.stderr
@@ -0,0 +1,8 @@
+error: invalid macro matcher; matchers must be contained in balanced delimiters
+  --> $DIR/macro-missing-delimiters.rs:2:5
+   |
+LL |     baz => ()
+   |     ^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs
new file mode 100644
index 00000000000..c1e6ba74647
--- /dev/null
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Zdeduplicate-diagnostics=yes
+
+macro_rules! m {
+    ($name) => {}
+    //~^ ERROR missing fragment
+    //~| ERROR missing fragment
+    //~| WARN this was previously accepted
+}
+
+fn main() {
+    m!();
+    m!();
+    m!();
+    m!();
+}
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
new file mode 100644
index 00000000000..3b9e716e194
--- /dev/null
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
@@ -0,0 +1,18 @@
+error: missing fragment specifier
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {}
+   |      ^^^^^
+
+error: missing fragment specifier
+  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
+   |
+LL |     ($name) => {}
+   |      ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs
new file mode 100644
index 00000000000..210c85ebbf2
--- /dev/null
+++ b/tests/ui/macros/macro-missing-fragment.rs
@@ -0,0 +1,26 @@
+#![warn(missing_fragment_specifier)]
+
+macro_rules! used_arm {
+    ( $( any_token $field_rust_type )* ) => {};
+    //~^ ERROR missing fragment
+    //~| WARN missing fragment
+    //~| WARN this was previously accepted
+}
+
+macro_rules! used_macro_unused_arm {
+    () => {};
+    ( $name ) => {};
+    //~^ WARN missing fragment
+    //~| WARN this was previously accepted
+}
+
+macro_rules! unused_macro {
+    ( $name ) => {};
+    //~^ WARN missing fragment
+    //~| WARN this was previously accepted
+}
+
+fn main() {
+    used_arm!();
+    used_macro_unused_arm!();
+}
diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.stderr
new file mode 100644
index 00000000000..2aa1e58f6b1
--- /dev/null
+++ b/tests/ui/macros/macro-missing-fragment.stderr
@@ -0,0 +1,40 @@
+error: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:4:20
+   |
+LL |     ( $( any_token $field_rust_type )* ) => {};
+   |                    ^^^^^^^^^^^^^^^^
+
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:4:20
+   |
+LL |     ( $( any_token $field_rust_type )* ) => {};
+   |                    ^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+note: the lint level is defined here
+  --> $DIR/macro-missing-fragment.rs:1:9
+   |
+LL | #![warn(missing_fragment_specifier)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:12:7
+   |
+LL |     ( $name ) => {};
+   |       ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+
+warning: missing fragment specifier
+  --> $DIR/macro-missing-fragment.rs:18:7
+   |
+LL |     ( $name ) => {};
+   |       ^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
+
+error: aborting due to previous error; 3 warnings emitted
+
diff --git a/tests/ui/macros/macro-multiple-items.rs b/tests/ui/macros/macro-multiple-items.rs
new file mode 100644
index 00000000000..3b6dfd9bc5e
--- /dev/null
+++ b/tests/ui/macros/macro-multiple-items.rs
@@ -0,0 +1,16 @@
+// run-pass
+macro_rules! make_foo {
+    () => (
+        struct Foo;
+
+        impl Foo {
+            fn bar(&self) {}
+        }
+    )
+}
+
+make_foo!();
+
+pub fn main() {
+    Foo.bar()
+}
diff --git a/tests/ui/macros/macro-multiple-matcher-bindings.rs b/tests/ui/macros/macro-multiple-matcher-bindings.rs
new file mode 100644
index 00000000000..7d39dc0a52f
--- /dev/null
+++ b/tests/ui/macros/macro-multiple-matcher-bindings.rs
@@ -0,0 +1,21 @@
+// Test that duplicate matcher binding names are caught at declaration time, rather than at macro
+// invocation time.
+
+#![allow(unused_macros)]
+
+macro_rules! foo1 {
+    ($a:ident, $a:ident) => {}; //~ERROR duplicate matcher binding
+    ($a:ident, $a:path) => {};  //~ERROR duplicate matcher binding
+}
+
+macro_rules! foo2 {
+    ($a:ident) => {}; // OK
+    ($a:path) => {};  // OK
+}
+
+macro_rules! foo3 {
+    ($a:ident, $($a:ident),*) => {}; //~ERROR duplicate matcher binding
+    ($($a:ident)+ # $($($a:path),+);*) => {}; //~ERROR duplicate matcher binding
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-multiple-matcher-bindings.stderr b/tests/ui/macros/macro-multiple-matcher-bindings.stderr
new file mode 100644
index 00000000000..3ad1297ffb2
--- /dev/null
+++ b/tests/ui/macros/macro-multiple-matcher-bindings.stderr
@@ -0,0 +1,34 @@
+error: duplicate matcher binding
+  --> $DIR/macro-multiple-matcher-bindings.rs:7:16
+   |
+LL |     ($a:ident, $a:ident) => {};
+   |      --------  ^^^^^^^^ duplicate binding
+   |      |
+   |      previous binding
+
+error: duplicate matcher binding
+  --> $DIR/macro-multiple-matcher-bindings.rs:8:16
+   |
+LL |     ($a:ident, $a:path) => {};
+   |      --------  ^^^^^^^ duplicate binding
+   |      |
+   |      previous binding
+
+error: duplicate matcher binding
+  --> $DIR/macro-multiple-matcher-bindings.rs:17:18
+   |
+LL |     ($a:ident, $($a:ident),*) => {};
+   |      --------    ^^^^^^^^ duplicate binding
+   |      |
+   |      previous binding
+
+error: duplicate matcher binding
+  --> $DIR/macro-multiple-matcher-bindings.rs:18:25
+   |
+LL |     ($($a:ident)+ # $($($a:path),+);*) => {};
+   |        --------         ^^^^^^^ duplicate binding
+   |        |
+   |        previous binding
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/macro-name-typo.rs b/tests/ui/macros/macro-name-typo.rs
new file mode 100644
index 00000000000..1ddc419d302
--- /dev/null
+++ b/tests/ui/macros/macro-name-typo.rs
@@ -0,0 +1,3 @@
+fn main() {
+    printlx!("oh noes!"); //~ ERROR cannot find
+}
diff --git a/tests/ui/macros/macro-name-typo.stderr b/tests/ui/macros/macro-name-typo.stderr
new file mode 100644
index 00000000000..d7c8aaae22e
--- /dev/null
+++ b/tests/ui/macros/macro-name-typo.stderr
@@ -0,0 +1,11 @@
+error: cannot find macro `printlx` in this scope
+  --> $DIR/macro-name-typo.rs:2:5
+   |
+LL |     printlx!("oh noes!");
+   |     ^^^^^^^ help: a macro with a similar name exists: `println`
+  --> $SRC_DIR/std/src/macros.rs:LL:COL
+   |
+   = note: similarly named macro `println` defined here
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-named-default.rs b/tests/ui/macros/macro-named-default.rs
new file mode 100644
index 00000000000..9b6cd191640
--- /dev/null
+++ b/tests/ui/macros/macro-named-default.rs
@@ -0,0 +1,18 @@
+// run-pass
+macro_rules! default {
+    ($($x:tt)*) => { $($x)* }
+}
+
+default! {
+    struct A;
+}
+
+impl A {
+    default! {
+        fn foo(&self) {}
+    }
+}
+
+fn main() {
+    A.foo();
+}
diff --git a/tests/ui/macros/macro-nested_definition_issue-31946.rs b/tests/ui/macros/macro-nested_definition_issue-31946.rs
new file mode 100644
index 00000000000..a83c5b2e44f
--- /dev/null
+++ b/tests/ui/macros/macro-nested_definition_issue-31946.rs
@@ -0,0 +1,9 @@
+// run-pass
+fn main() {
+    println!("{}", {
+        macro_rules! foo {
+            ($name:expr) => { concat!("hello ", $name) }
+        }
+        foo!("rust")
+    });
+}
diff --git a/tests/ui/macros/macro-nested_expr.rs b/tests/ui/macros/macro-nested_expr.rs
new file mode 100644
index 00000000000..f1433cbf4f9
--- /dev/null
+++ b/tests/ui/macros/macro-nested_expr.rs
@@ -0,0 +1,22 @@
+// run-pass
+// #42164
+
+#![feature(decl_macro)]
+#![allow(dead_code)]
+
+pub macro m($inner_str:expr) {
+    #[doc = $inner_str]
+    struct S;
+}
+
+macro_rules! define_f {
+    ($name:expr) => {
+        #[export_name = $name]
+        fn f() {}
+    }
+}
+
+fn main() {
+    define_f!(concat!("exported_", "f"));
+    m!(stringify!(foo));
+}
diff --git a/tests/ui/macros/macro-nested_stmt_macros.rs b/tests/ui/macros/macro-nested_stmt_macros.rs
new file mode 100644
index 00000000000..5d4758a0c7b
--- /dev/null
+++ b/tests/ui/macros/macro-nested_stmt_macros.rs
@@ -0,0 +1,23 @@
+// run-pass
+macro_rules! foo {
+    () => {
+        struct Bar;
+        struct Baz;
+    }
+}
+
+macro_rules! grault {
+    () => {
+        foo!();
+        struct Xyzzy;
+    }
+}
+
+fn static_assert_exists<T>() { }
+
+fn main() {
+    grault!();
+    static_assert_exists::<Bar>();
+    static_assert_exists::<Baz>();
+    static_assert_exists::<Xyzzy>();
+}
diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs
new file mode 100644
index 00000000000..26e1f2afa91
--- /dev/null
+++ b/tests/ui/macros/macro-non-lifetime.rs
@@ -0,0 +1,8 @@
+// Test for issue #50381: non-lifetime passed to :lifetime.
+
+macro_rules! m { ($x:lifetime) => { } }
+
+fn main() {
+    m!(a);
+    //~^ ERROR no rules expected the token `a`
+}
diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr
new file mode 100644
index 00000000000..e1ed87f9435
--- /dev/null
+++ b/tests/ui/macros/macro-non-lifetime.stderr
@@ -0,0 +1,17 @@
+error: no rules expected the token `a`
+  --> $DIR/macro-non-lifetime.rs:6:8
+   |
+LL | macro_rules! m { ($x:lifetime) => { } }
+   | -------------- when calling this macro
+...
+LL |     m!(a);
+   |        ^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$x:lifetime`
+  --> $DIR/macro-non-lifetime.rs:3:19
+   |
+LL | macro_rules! m { ($x:lifetime) => { } }
+   |                   ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-nt-list.rs b/tests/ui/macros/macro-nt-list.rs
new file mode 100644
index 00000000000..36aa74f0825
--- /dev/null
+++ b/tests/ui/macros/macro-nt-list.rs
@@ -0,0 +1,21 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+macro_rules! list {
+    ( ($($id:ident),*) ) => (());
+    ( [$($id:ident),*] ) => (());
+    ( {$($id:ident),*} ) => (());
+}
+
+macro_rules! tt_list {
+    ( ($($tt:tt),*) ) => (());
+}
+
+pub fn main() {
+    list!( () );
+    list!( [] );
+    list!( {} );
+
+    tt_list!( (a, b, c) );
+    tt_list!( () );
+}
diff --git a/tests/ui/macros/macro-of-higher-order.rs b/tests/ui/macros/macro-of-higher-order.rs
new file mode 100644
index 00000000000..ec551d6cdbc
--- /dev/null
+++ b/tests/ui/macros/macro-of-higher-order.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+macro_rules! higher_order {
+    (subst $lhs:tt => $rhs:tt) => ({
+            macro_rules! anon { $lhs => $rhs }
+            anon!(1_usize, 2_usize, "foo")
+    });
+}
+
+macro_rules! outer {
+    ($x:expr; $fragment:ident) => {
+        macro_rules! inner { ($y:$fragment) => { $x + $y } }
+    }
+}
+
+fn main() {
+    let val = higher_order!(subst ($x:expr, $y:expr, $foo:expr) => (($x + $y, $foo)));
+    assert_eq!(val, (3, "foo"));
+
+    outer!(2; expr);
+    assert_eq!(inner!(3), 5);
+}
diff --git a/tests/ui/macros/macro-or-patterns-back-compat.fixed b/tests/ui/macros/macro-or-patterns-back-compat.fixed
new file mode 100644
index 00000000000..b0d56e9bb1e
--- /dev/null
+++ b/tests/ui/macros/macro-or-patterns-back-compat.fixed
@@ -0,0 +1,39 @@
+// run-rustfix
+// aux-build:or-pattern.rs
+
+#![deny(rust_2021_incompatible_or_patterns)]
+#![allow(unused_macros)]
+
+#[macro_use]
+extern crate or_pattern;
+
+macro_rules! foo { ($x:pat_param | $y:pat) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+macro_rules! bar { ($($x:pat_param)+ | $($y:pat)+) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat_param | $y:pat_param) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+macro_rules! match_any {
+    ( $expr:expr , $( $( $pat:pat_param )|+ => $expr_arm:expr ),+ ) => {
+        //~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+        //~| WARN this is accepted in the current edition
+        match $expr {
+            $(
+                $( $pat => $expr_arm, )+
+            )+
+        }
+    };
+}
+
+fn main() {
+    let result: Result<i64, i32> = Err(42);
+    let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+    assert_eq!(int, 42);
+    a!(1|);
+}
diff --git a/tests/ui/macros/macro-or-patterns-back-compat.rs b/tests/ui/macros/macro-or-patterns-back-compat.rs
new file mode 100644
index 00000000000..9e24b5106b8
--- /dev/null
+++ b/tests/ui/macros/macro-or-patterns-back-compat.rs
@@ -0,0 +1,39 @@
+// run-rustfix
+// aux-build:or-pattern.rs
+
+#![deny(rust_2021_incompatible_or_patterns)]
+#![allow(unused_macros)]
+
+#[macro_use]
+extern crate or_pattern;
+
+macro_rules! foo { ($x:pat | $y:pat) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
+//~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+//~| WARN this is accepted in the current edition
+macro_rules! match_any {
+    ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
+        //~^ ERROR the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+        //~| WARN this is accepted in the current edition
+        match $expr {
+            $(
+                $( $pat => $expr_arm, )+
+            )+
+        }
+    };
+}
+
+fn main() {
+    let result: Result<i64, i32> = Err(42);
+    let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+    assert_eq!(int, 42);
+    a!(1|);
+}
diff --git a/tests/ui/macros/macro-or-patterns-back-compat.stderr b/tests/ui/macros/macro-or-patterns-back-compat.stderr
new file mode 100644
index 00000000000..e04dfefa4e8
--- /dev/null
+++ b/tests/ui/macros/macro-or-patterns-back-compat.stderr
@@ -0,0 +1,43 @@
+error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+  --> $DIR/macro-or-patterns-back-compat.rs:10:21
+   |
+LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
+   |                     ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+note: the lint level is defined here
+  --> $DIR/macro-or-patterns-back-compat.rs:4:9
+   |
+LL | #![deny(rust_2021_incompatible_or_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+  --> $DIR/macro-or-patterns-back-compat.rs:13:23
+   |
+LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
+   |                       ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+
+error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+  --> $DIR/macro-or-patterns-back-compat.rs:19:21
+   |
+LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
+   |                     ^^^^^^ help: use pat_param to preserve semantics: `$x:pat_param`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+
+error: the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+  --> $DIR/macro-or-patterns-back-compat.rs:23:26
+   |
+LL |     ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
+   |                          ^^^^^^^^ help: use pat_param to preserve semantics: `$pat:pat_param`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs
new file mode 100644
index 00000000000..0752f7e3153
--- /dev/null
+++ b/tests/ui/macros/macro-outer-attributes.rs
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs)]
+
+macro_rules! test { ($nm:ident,
+                     #[$a:meta],
+                     $i:item) => (mod $nm { #[$a] $i }); }
+
+test!(a,
+      #[cfg(qux)],
+      pub fn bar() { });
+
+test!(b,
+      #[cfg(not(qux))],
+      pub fn bar() { });
+
+// test1!(#[bar])
+#[rustc_dummy]
+fn main() {
+    a::bar(); //~ ERROR cannot find function `bar` in module `a`
+    b::bar();
+}
diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr
new file mode 100644
index 00000000000..4ea760ab82b
--- /dev/null
+++ b/tests/ui/macros/macro-outer-attributes.stderr
@@ -0,0 +1,19 @@
+error[E0425]: cannot find function `bar` in module `a`
+  --> $DIR/macro-outer-attributes.rs:18:8
+   |
+LL |     a::bar();
+   |        ^^^ not found in `a`
+   |
+help: consider importing this function
+   |
+LL | use b::bar;
+   |
+help: if you import `bar`, refer to it directly
+   |
+LL -     a::bar();
+LL +     bar();
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/macros/macro-parameter-span.rs b/tests/ui/macros/macro-parameter-span.rs
new file mode 100644
index 00000000000..5609f84e141
--- /dev/null
+++ b/tests/ui/macros/macro-parameter-span.rs
@@ -0,0 +1,13 @@
+macro_rules! foo {
+    ($id: ident) => {
+        $id
+    }
+}
+
+// Testing that the error span points to the parameter 'x' in the callsite,
+// not to the macro variable '$id'
+fn main() {
+    foo!(
+        x //~ ERROR cannot find value `x` in this scope
+        );
+}
diff --git a/tests/ui/macros/macro-parameter-span.stderr b/tests/ui/macros/macro-parameter-span.stderr
new file mode 100644
index 00000000000..24e3e89ea9b
--- /dev/null
+++ b/tests/ui/macros/macro-parameter-span.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/macro-parameter-span.rs:11:9
+   |
+LL |         x
+   |         ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/macros/macro-pat-follow-2018.rs b/tests/ui/macros/macro-pat-follow-2018.rs
new file mode 100644
index 00000000000..ce2911de986
--- /dev/null
+++ b/tests/ui/macros/macro-pat-follow-2018.rs
@@ -0,0 +1,15 @@
+// run-pass
+// edition:2018
+
+macro_rules! pat_bar {
+    ($p:pat | $p2:pat) => {{
+        match Some(1u8) {
+            $p | $p2 => {}
+            _ => {}
+        }
+    }};
+}
+
+fn main() {
+    pat_bar!(Some(1u8) | None);
+}
diff --git a/tests/ui/macros/macro-pat-follow.rs b/tests/ui/macros/macro-pat-follow.rs
new file mode 100644
index 00000000000..8e02789fdd8
--- /dev/null
+++ b/tests/ui/macros/macro-pat-follow.rs
@@ -0,0 +1,21 @@
+// run-pass
+macro_rules! pat_in {
+    ($p:pat in $e:expr) => {{
+        let mut iter = $e.into_iter();
+        while let $p = iter.next() {}
+    }};
+}
+
+macro_rules! pat_if {
+    ($p:pat if $e:expr) => {{
+        match Some(1u8) {
+            $p if $e => {}
+            _ => {}
+        }
+    }};
+}
+
+fn main() {
+    pat_in!(Some(_) in 0..10);
+    pat_if!(Some(x) if x > 0);
+}
diff --git a/tests/ui/macros/macro-pat-neg-lit.rs b/tests/ui/macros/macro-pat-neg-lit.rs
new file mode 100644
index 00000000000..79c68fd2541
--- /dev/null
+++ b/tests/ui/macros/macro-pat-neg-lit.rs
@@ -0,0 +1,25 @@
+// run-pass
+macro_rules! enum_number {
+    ($name:ident { $($variant:ident = $value:expr, )* }) => {
+        enum $name {
+            $($variant = $value,)*
+        }
+
+        fn foo(value: i32) -> Option<$name> {
+            match value {
+                $( $value => Some($name::$variant), )*
+                _ => None
+            }
+        }
+    }
+}
+
+enum_number!(Change {
+    Down = -1,
+    None = 0,
+    Up = 1,
+});
+
+fn main() {
+    if let Some(Change::Down) = foo(-1) {} else { panic!() }
+}
diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs
new file mode 100644
index 00000000000..f5a97eca21b
--- /dev/null
+++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.rs
@@ -0,0 +1,20 @@
+// edition:2021
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok
+macro_rules! match_any {
+    ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { //~ ERROR `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+        match $expr {
+            $(
+                $( $pat => $expr_arm, )+
+            )+
+        }
+    };
+}
+
+fn main() {
+    let result: Result<i64, i32> = Err(42);
+    let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+    assert_eq!(int, 42);
+}
diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
new file mode 100644
index 00000000000..a06487be3d6
--- /dev/null
+++ b/tests/ui/macros/macro-pat-pattern-followed-by-or-in-2021.stderr
@@ -0,0 +1,32 @@
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:3:28
+   |
+LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:4:32
+   |
+LL | macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} }
+   |                       ------   ^ not allowed after `pat` fragments
+   |                       |
+   |                       help: try a `pat_param` fragment specifier instead: `$x:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat-pattern-followed-by-or-in-2021.rs:7:36
+   |
+LL |     ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
+   |                          --------  ^ not allowed after `pat` fragments
+   |                          |
+   |                          help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/macro-pat-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs
new file mode 100644
index 00000000000..54bd13d7ebc
--- /dev/null
+++ b/tests/ui/macros/macro-pat-pattern-followed-by-or.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat | $y:pat) => {} } // should be ok
+macro_rules! bar { ($($x:pat)+ | $($y:pat)+) => {} } // should be ok
+macro_rules! qux { ($x:pat, $y:pat) => {} } // should be ok
+macro_rules! match_any {
+    ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => { // should be ok
+        match $expr {
+            $(
+                $( $pat => $expr_arm, )+
+            )+
+        }
+    };
+}
+
+fn main() {
+    let result: Result<i64, i32> = Err(42);
+    let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+    assert_eq!(int, 42);
+}
diff --git a/tests/ui/macros/macro-pat.rs b/tests/ui/macros/macro-pat.rs
new file mode 100644
index 00000000000..baf816e53ea
--- /dev/null
+++ b/tests/ui/macros/macro-pat.rs
@@ -0,0 +1,65 @@
+// run-pass
+
+macro_rules! mypat {
+    () => (
+        Some('y')
+    )
+}
+
+macro_rules! char_x {
+    () => (
+        'x'
+    )
+}
+
+macro_rules! some {
+    ($x:pat) => (
+        Some($x)
+    )
+}
+
+macro_rules! indirect {
+    () => (
+        some!(char_x!())
+    )
+}
+
+macro_rules! ident_pat {
+    ($x:ident) => (
+        $x
+    )
+}
+
+fn f(c: Option<char>) -> usize {
+    match c {
+        Some('x') => 1,
+        mypat!() => 2,
+        _ => 3,
+    }
+}
+
+pub fn main() {
+    assert_eq!(1, f(Some('x')));
+    assert_eq!(2, f(Some('y')));
+    assert_eq!(3, f(None));
+
+    assert_eq!(1, match Some('x') {
+        Some(char_x!()) => 1,
+        _ => 2,
+    });
+
+    assert_eq!(1, match Some('x') {
+        some!(char_x!()) => 1,
+        _ => 2,
+    });
+
+    assert_eq!(1, match Some('x') {
+        indirect!() => 1,
+        _ => 2,
+    });
+
+    assert_eq!(3, {
+        let ident_pat!(x) = 2;
+        x+1
+    });
+}
diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs
new file mode 100644
index 00000000000..b4be03aaddd
--- /dev/null
+++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.rs
@@ -0,0 +1,22 @@
+// edition:2021
+
+#![allow(unused_macros)]
+macro_rules! foo { ($x:pat | $y:pat) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! baz { ($x:pat_param | $y:pat_param) => {} } // should be ok
+macro_rules! qux { ($x:pat_param | $y:pat) => {} } // should be ok
+macro_rules! ogg { ($x:pat | $y:pat_param) => {} } //~ ERROR `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+macro_rules! match_any {
+    ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => { //~ ERROR  `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+        match $expr {
+            $(
+                $( $pat => $expr_arm, )+
+            )+
+        }
+    };
+}
+
+fn main() {
+    let result: Result<i64, i32> = Err(42);
+    let int: i64 = match_any!(result, Ok(i) | Err(i) => i.into());
+    assert_eq!(int, 42);
+}
diff --git a/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
new file mode 100644
index 00000000000..c3754dde080
--- /dev/null
+++ b/tests/ui/macros/macro-pat2021-pattern-followed-by-or.stderr
@@ -0,0 +1,32 @@
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:4:28
+   |
+LL | macro_rules! foo { ($x:pat | $y:pat) => {} }
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$x:pat` is followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:7:28
+   |
+LL | macro_rules! ogg { ($x:pat | $y:pat_param) => {} }
+   |                     ------ ^ not allowed after `pat` fragments
+   |                     |
+   |                     help: try a `pat_param` fragment specifier instead: `$x:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: `$pat:pat` may be followed by `|`, which is not allowed for `pat` fragments
+  --> $DIR/macro-pat2021-pattern-followed-by-or.rs:9:35
+   |
+LL |     ( $expr:expr , $( $( $pat:pat)|+ => $expr_arm:pat),+ ) => {
+   |                          -------- ^ not allowed after `pat` fragments
+   |                          |
+   |                          help: try a `pat_param` fragment specifier instead: `$pat:pat_param`
+   |
+   = note: allowed there are: `=>`, `,`, `=`, `if` or `in`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/macro-path-prelude-fail-1.rs b/tests/ui/macros/macro-path-prelude-fail-1.rs
new file mode 100644
index 00000000000..d93792bdfe3
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-1.rs
@@ -0,0 +1,8 @@
+mod m {
+    fn check() {
+        Vec::clone!(); //~ ERROR failed to resolve: `Vec` is a struct, not a module
+        u8::clone!(); //~ ERROR failed to resolve: `u8` is a builtin type, not a module
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-path-prelude-fail-1.stderr b/tests/ui/macros/macro-path-prelude-fail-1.stderr
new file mode 100644
index 00000000000..f8377ffb355
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-1.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: `Vec` is a struct, not a module
+  --> $DIR/macro-path-prelude-fail-1.rs:3:9
+   |
+LL |         Vec::clone!();
+   |         ^^^ `Vec` is a struct, not a module
+
+error[E0433]: failed to resolve: `u8` is a builtin type, not a module
+  --> $DIR/macro-path-prelude-fail-1.rs:4:9
+   |
+LL |         u8::clone!();
+   |         ^^ `u8` is a builtin type, not a module
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/macro-path-prelude-fail-2.rs b/tests/ui/macros/macro-path-prelude-fail-2.rs
new file mode 100644
index 00000000000..816a3c4ccc0
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-2.rs
@@ -0,0 +1,7 @@
+mod m {
+    fn check() {
+        Result::Ok!(); //~ ERROR failed to resolve: partially resolved path in a macro
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-path-prelude-fail-2.stderr b/tests/ui/macros/macro-path-prelude-fail-2.stderr
new file mode 100644
index 00000000000..9574b7a1e25
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-2.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: partially resolved path in a macro
+  --> $DIR/macro-path-prelude-fail-2.rs:3:9
+   |
+LL |         Result::Ok!();
+   |         ^^^^^^^^^^ partially resolved path in a macro
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/macro-path-prelude-fail-3.rs b/tests/ui/macros/macro-path-prelude-fail-3.rs
new file mode 100644
index 00000000000..68eb350a956
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-3.rs
@@ -0,0 +1,3 @@
+fn main() {
+    inline!(); //~ ERROR cannot find macro `inline` in this scope
+}
diff --git a/tests/ui/macros/macro-path-prelude-fail-3.stderr b/tests/ui/macros/macro-path-prelude-fail-3.stderr
new file mode 100644
index 00000000000..f1c3512bc9b
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-3.stderr
@@ -0,0 +1,13 @@
+error: cannot find macro `inline` in this scope
+  --> $DIR/macro-path-prelude-fail-3.rs:2:5
+   |
+LL |     inline!();
+   |     ^^^^^^ help: a macro with a similar name exists: `line`
+  --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+   = note: similarly named macro `line` defined here
+   |
+   = note: `inline` is in scope, but it is an attribute: `#[inline]`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-path-prelude-fail-4.rs b/tests/ui/macros/macro-path-prelude-fail-4.rs
new file mode 100644
index 00000000000..0f93fcdaa5f
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-4.rs
@@ -0,0 +1,4 @@
+#[derive(inline)] //~ ERROR expected derive macro, found built-in attribute `inline`
+struct S;
+
+fn main() {}
diff --git a/tests/ui/macros/macro-path-prelude-fail-4.stderr b/tests/ui/macros/macro-path-prelude-fail-4.stderr
new file mode 100644
index 00000000000..dfd6818b678
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-fail-4.stderr
@@ -0,0 +1,8 @@
+error: expected derive macro, found built-in attribute `inline`
+  --> $DIR/macro-path-prelude-fail-4.rs:1:10
+   |
+LL | #[derive(inline)]
+   |          ^^^^^^ not a derive macro
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-path-prelude-pass.rs b/tests/ui/macros/macro-path-prelude-pass.rs
new file mode 100644
index 00000000000..7cf346286ea
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-pass.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+mod m {
+    fn check() {
+        std::panic!(); // OK
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-path-prelude-shadowing.rs b/tests/ui/macros/macro-path-prelude-shadowing.rs
new file mode 100644
index 00000000000..d7181200085
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-shadowing.rs
@@ -0,0 +1,33 @@
+// aux-build:macro-in-other-crate.rs
+
+#![feature(decl_macro)]
+
+macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
+    #[macro_use]
+    extern crate macro_in_other_crate;
+}}
+
+add_macro_expanded_things_to_macro_prelude!();
+
+mod m1 {
+    fn check() {
+        inline!(); // OK. Theoretically ambiguous, but we do not consider built-in attributes
+                   // as candidates for non-attribute macro invocations to avoid regressions
+                   // on stable channel
+    }
+}
+
+mod m2 {
+    pub mod std {
+        pub macro panic() {}
+    }
+}
+
+mod m3 {
+    use m2::*; // glob-import user-defined `std`
+    fn check() {
+        std::panic!(); //~ ERROR `std` is ambiguous
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-path-prelude-shadowing.stderr b/tests/ui/macros/macro-path-prelude-shadowing.stderr
new file mode 100644
index 00000000000..4a864c2e927
--- /dev/null
+++ b/tests/ui/macros/macro-path-prelude-shadowing.stderr
@@ -0,0 +1,19 @@
+error[E0659]: `std` is ambiguous
+  --> $DIR/macro-path-prelude-shadowing.rs:29:9
+   |
+LL |         std::panic!();
+   |         ^^^ ambiguous name
+   |
+   = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
+   = note: `std` could refer to a built-in crate
+note: `std` could also refer to the module imported here
+  --> $DIR/macro-path-prelude-shadowing.rs:27:9
+   |
+LL |     use m2::*; // glob-import user-defined `std`
+   |         ^^^^^
+   = help: consider adding an explicit import of `std` to disambiguate
+   = help: or use `self::std` to refer to this module unambiguously
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/macro-path.rs b/tests/ui/macros/macro-path.rs
new file mode 100644
index 00000000000..6c011c897da
--- /dev/null
+++ b/tests/ui/macros/macro-path.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+
+mod m {
+    pub type t = isize;
+}
+
+macro_rules! foo {
+    ($p:path) => ({
+        fn f() -> $p { 10 }
+        f()
+    })
+}
+
+pub fn main() {
+    assert_eq!(foo!(m::t), 10);
+}
diff --git a/tests/ui/macros/macro-pub-matcher.rs b/tests/ui/macros/macro-pub-matcher.rs
new file mode 100644
index 00000000000..7b02a70be09
--- /dev/null
+++ b/tests/ui/macros/macro-pub-matcher.rs
@@ -0,0 +1,117 @@
+// run-pass
+#![allow(dead_code, unused_imports, unused_macro_rules)]
+
+/**
+Ensure that `:vis` matches can be captured in existing positions, and passed
+through without the need for reparse tricks.
+*/
+macro_rules! vis_passthru {
+    ($vis:vis const $name:ident: $ty:ty = $e:expr;) => { $vis const $name: $ty = $e; };
+    ($vis:vis enum $name:ident {}) => { $vis struct $name {} };
+    ($vis:vis extern "C" fn $name:ident() {}) => { $vis extern "C" fn $name() {} };
+    ($vis:vis fn $name:ident() {}) => { $vis fn $name() {} };
+    ($vis:vis mod $name:ident {}) => { $vis mod $name {} };
+    ($vis:vis static $name:ident: $ty:ty = $e:expr;) => { $vis static $name: $ty = $e; };
+    ($vis:vis struct $name:ident;) => { $vis struct $name; };
+    ($vis:vis trait $name:ident {}) => { $vis trait $name {} };
+    ($vis:vis type $name:ident = $ty:ty;) => { $vis type $name = $ty; };
+    ($vis:vis use $path:ident as $name:ident;) => { $vis use self::$path as $name; };
+}
+
+mod with_pub {
+    vis_passthru! { pub const A: i32 = 0; }
+    vis_passthru! { pub enum B {} }
+    vis_passthru! { pub extern "C" fn c() {} }
+    vis_passthru! { pub mod d {} }
+    vis_passthru! { pub static E: i32 = 0; }
+    vis_passthru! { pub struct F; }
+    vis_passthru! { pub trait G {} }
+    vis_passthru! { pub type H = i32; }
+    vis_passthru! { pub use A as I; }
+}
+
+mod without_pub {
+    vis_passthru! { const A: i32 = 0; }
+    vis_passthru! { enum B {} }
+    vis_passthru! { extern "C" fn c() {} }
+    vis_passthru! { mod d {} }
+    vis_passthru! { static E: i32 = 0; }
+    vis_passthru! { struct F; }
+    vis_passthru! { trait G {} }
+    vis_passthru! { type H = i32; }
+    vis_passthru! { use A as I; }
+}
+
+mod with_pub_restricted {
+    vis_passthru! { pub(crate) const A: i32 = 0; }
+    vis_passthru! { pub(crate) enum B {} }
+    vis_passthru! { pub(crate) extern "C" fn c() {} }
+    vis_passthru! { pub(crate) mod d {} }
+    vis_passthru! { pub(crate) static E: i32 = 0; }
+    vis_passthru! { pub(crate) struct F; }
+    vis_passthru! { pub(crate) trait G {} }
+    vis_passthru! { pub(crate) type H = i32; }
+    vis_passthru! { pub(crate) use A as I; }
+}
+
+mod with_crate {
+    vis_passthru! { pub(crate) const A: i32 = 0; }
+    vis_passthru! { pub(crate) enum B {} }
+    vis_passthru! { pub(crate) extern "C" fn c() {} }
+    vis_passthru! { pub(crate) mod d {} }
+    vis_passthru! { pub(crate) static E: i32 = 0; }
+    vis_passthru! { pub(crate) struct F; }
+    vis_passthru! { pub(crate) trait G {} }
+    vis_passthru! { pub(crate) type H = i32; }
+    vis_passthru! { pub(crate) use A as I; }
+}
+
+mod garden {
+    mod with_pub_restricted_path {
+        vis_passthru! { pub(in garden) const A: i32 = 0; }
+        vis_passthru! { pub(in garden) enum B {} }
+        vis_passthru! { pub(in garden) extern "C" fn c() {} }
+        vis_passthru! { pub(in garden) mod d {} }
+        vis_passthru! { pub(in garden) static E: i32 = 0; }
+        vis_passthru! { pub(in garden) struct F; }
+        vis_passthru! { pub(in garden) trait G {} }
+        vis_passthru! { pub(in garden) type H = i32; }
+        vis_passthru! { pub(in garden) use A as I; }
+    }
+}
+
+/*
+Ensure that the `:vis` matcher works in a more complex situation: parsing a
+struct definition.
+*/
+macro_rules! vis_parse_struct {
+    ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident {$($body:tt)*}) => {
+        vis_parse_struct! { @parse_fields $(#[$($attrs)*])*, $vis, $name, $($body)* }
+    };
+
+    ($(#[$($attrs:tt)*])* $vis:vis struct $name:ident ($($body:tt)*);) => {
+        vis_parse_struct! { @parse_tuple $(#[$($attrs)*])*, $vis, $name, $($body)* }
+    };
+
+    (@parse_fields
+     $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fname:ident: $fty:ty),* $(,)*) => {
+        $(#[$attrs])* $vis struct $name { $($fvis $fname: $fty,)* }
+    };
+
+    (@parse_tuple
+     $(#[$attrs:meta])*, $vis:vis, $name:ident, $($fvis:vis $fty:ty),* $(,)*) => {
+        $(#[$attrs])* $vis struct $name ( $($fvis $fty,)* );
+    };
+}
+
+mod test_struct {
+    vis_parse_struct! { pub(crate) struct A { pub a: i32, b: i32, pub(crate) c: i32 } }
+    vis_parse_struct! { pub struct B { a: i32, pub(crate) b: i32, pub c: i32 } }
+    vis_parse_struct! { struct C { pub(crate) a: i32, pub b: i32, c: i32 } }
+
+    vis_parse_struct! { pub(crate) struct D (pub i32, i32, pub(crate) i32); }
+    vis_parse_struct! { pub struct E (i32, pub(crate) i32, pub i32); }
+    vis_parse_struct! { struct F (pub(crate) i32, pub i32, i32); }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs
new file mode 100644
index 00000000000..874c94d08e0
--- /dev/null
+++ b/tests/ui/macros/macro-reexport-removed.rs
@@ -0,0 +1,8 @@
+// aux-build:two_macros.rs
+
+#![feature(macro_reexport)] //~ ERROR feature has been removed
+
+#[macro_reexport(macro_one)] //~ ERROR cannot find attribute `macro_reexport` in this scope
+extern crate two_macros;
+
+fn main() {}
diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr
new file mode 100644
index 00000000000..475a586ddc0
--- /dev/null
+++ b/tests/ui/macros/macro-reexport-removed.stderr
@@ -0,0 +1,17 @@
+error[E0557]: feature has been removed
+  --> $DIR/macro-reexport-removed.rs:3:12
+   |
+LL | #![feature(macro_reexport)]
+   |            ^^^^^^^^^^^^^^ feature has been removed
+   |
+   = note: subsumed by `pub use`
+
+error: cannot find attribute `macro_reexport` in this scope
+  --> $DIR/macro-reexport-removed.rs:5:3
+   |
+LL | #[macro_reexport(macro_one)]
+   |   ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0557`.
diff --git a/tests/ui/macros/macro-seq-followed-by-seq.rs b/tests/ui/macros/macro-seq-followed-by-seq.rs
new file mode 100644
index 00000000000..8f0f4fd4a0d
--- /dev/null
+++ b/tests/ui/macros/macro-seq-followed-by-seq.rs
@@ -0,0 +1,17 @@
+// run-pass
+// Test of allowing two sequences repetitions in a row,
+// functionality added as byproduct of RFC amendment #1384
+//   https://github.com/rust-lang/rfcs/pull/1384
+
+// Old version of Rust would reject this macro definition, even though
+// there are no local ambiguities (the initial `banana` and `orange`
+// tokens are enough for the expander to distinguish which case is
+// intended).
+macro_rules! foo {
+    ( $(banana $a:ident)* $(orange $b:tt)* ) => { };
+}
+
+fn main() {
+    foo!( banana id1 banana id2
+          orange hi  orange (hello world) );
+}
diff --git a/tests/ui/macros/macro-shadowing-relaxed.rs b/tests/ui/macros/macro-shadowing-relaxed.rs
new file mode 100644
index 00000000000..b2a639218b9
--- /dev/null
+++ b/tests/ui/macros/macro-shadowing-relaxed.rs
@@ -0,0 +1,25 @@
+// build-pass (FIXME(62277): could be check-pass?)
+// aux-build:macro-in-other-crate.rs
+
+#![feature(decl_macro)]
+
+macro_rules! my_include {() => {
+    // Outer
+    macro m() {}
+    #[macro_use(from_prelude)] extern crate macro_in_other_crate;
+
+    fn inner() {
+        // Inner
+        macro m() {}
+        macro_rules! from_prelude { () => {} }
+
+        // OK, both `m` and `from_prelude` are macro-expanded,
+        // but no more macro-expanded than their counterpart from outer scope.
+        m!();
+        from_prelude!();
+    }
+}}
+
+my_include!();
+
+fn main() {}
diff --git a/tests/ui/macros/macro-shadowing.rs b/tests/ui/macros/macro-shadowing.rs
new file mode 100644
index 00000000000..7f956dd7d10
--- /dev/null
+++ b/tests/ui/macros/macro-shadowing.rs
@@ -0,0 +1,26 @@
+// aux-build:two_macros.rs
+
+#![allow(unused_macros)]
+
+macro_rules! foo { () => {} }
+macro_rules! macro_one { () => {} }
+#[macro_use(macro_two)] extern crate two_macros;
+
+macro_rules! m1 { () => {
+    macro_rules! foo { () => {} }
+
+    #[macro_use] //~ ERROR `macro_two` is already in scope
+    extern crate two_macros as __;
+}}
+m1!();
+
+foo!(); //~ ERROR `foo` is ambiguous
+
+macro_rules! m2 { () => {
+    macro_rules! foo { () => {} }
+    foo!();
+}}
+m2!();
+//^ Since `foo` is not used outside this expansion, it is not a shadowing error.
+
+fn main() {}
diff --git a/tests/ui/macros/macro-shadowing.stderr b/tests/ui/macros/macro-shadowing.stderr
new file mode 100644
index 00000000000..a052b43ac10
--- /dev/null
+++ b/tests/ui/macros/macro-shadowing.stderr
@@ -0,0 +1,37 @@
+error: `macro_two` is already in scope
+  --> $DIR/macro-shadowing.rs:12:5
+   |
+LL |     #[macro_use]
+   |     ^^^^^^^^^^^^
+...
+LL | m1!();
+   | ----- in this macro invocation
+   |
+   = note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
+   = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `foo` is ambiguous
+  --> $DIR/macro-shadowing.rs:17:1
+   |
+LL | foo!();
+   | ^^^ ambiguous name
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `foo` could refer to the macro defined here
+  --> $DIR/macro-shadowing.rs:10:5
+   |
+LL |     macro_rules! foo { () => {} }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | m1!();
+   | ----- in this macro invocation
+note: `foo` could also refer to the macro defined here
+  --> $DIR/macro-shadowing.rs:5:1
+   |
+LL | macro_rules! foo { () => {} }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/macro-stability-rpass.rs b/tests/ui/macros/macro-stability-rpass.rs
new file mode 100644
index 00000000000..2d02b95288d
--- /dev/null
+++ b/tests/ui/macros/macro-stability-rpass.rs
@@ -0,0 +1,15 @@
+// run-pass
+// aux-build:unstable-macros.rs
+
+#![unstable(feature = "one_two_three_testing", issue = "none")]
+#![feature(staged_api, unstable_macros, local_unstable)]
+
+#[macro_use] extern crate unstable_macros;
+
+#[unstable(feature = "local_unstable", issue = "none")]
+macro_rules! local_unstable { () => () }
+
+fn main() {
+    unstable_macro!();
+    local_unstable!();
+}
diff --git a/tests/ui/macros/macro-stability.rs b/tests/ui/macros/macro-stability.rs
new file mode 100644
index 00000000000..ed7618a672b
--- /dev/null
+++ b/tests/ui/macros/macro-stability.rs
@@ -0,0 +1,31 @@
+// aux-build:unstable-macros.rs
+
+#![feature(decl_macro)]
+#![feature(staged_api)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[macro_use]
+extern crate unstable_macros;
+
+#[unstable(feature = "local_unstable", issue = "none")]
+macro_rules! local_unstable { () => () }
+
+#[unstable(feature = "local_unstable", issue = "none")]
+macro local_unstable_modern() {}
+
+#[stable(feature = "deprecated_macros", since = "1.0.0")]
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
+#[macro_export]
+macro_rules! local_deprecated{ () => () }
+
+fn main() {
+    local_unstable!(); //~ ERROR use of unstable library feature 'local_unstable'
+    local_unstable_modern!(); //~ ERROR use of unstable library feature 'local_unstable'
+    unstable_macro!(); //~ ERROR use of unstable library feature 'unstable_macros'
+    // unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
+
+    deprecated_macro!();
+    //~^ WARN use of deprecated macro `deprecated_macro`: deprecation note
+    local_deprecated!();
+    //~^ WARN use of deprecated macro `local_deprecated`: local deprecation note
+}
diff --git a/tests/ui/macros/macro-stability.stderr b/tests/ui/macros/macro-stability.stderr
new file mode 100644
index 00000000000..2cfdb52b174
--- /dev/null
+++ b/tests/ui/macros/macro-stability.stderr
@@ -0,0 +1,41 @@
+error[E0658]: use of unstable library feature 'local_unstable'
+  --> $DIR/macro-stability.rs:22:5
+   |
+LL |     local_unstable!();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(local_unstable)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'local_unstable'
+  --> $DIR/macro-stability.rs:23:5
+   |
+LL |     local_unstable_modern!();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(local_unstable)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_macros'
+  --> $DIR/macro-stability.rs:24:5
+   |
+LL |     unstable_macro!();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unstable_macros)]` to the crate attributes to enable
+
+warning: use of deprecated macro `deprecated_macro`: deprecation note
+  --> $DIR/macro-stability.rs:27:5
+   |
+LL |     deprecated_macro!();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+warning: use of deprecated macro `local_deprecated`: local deprecation note
+  --> $DIR/macro-stability.rs:29:5
+   |
+LL |     local_deprecated!();
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/macro-stmt-matchers.rs b/tests/ui/macros/macro-stmt-matchers.rs
new file mode 100644
index 00000000000..a643e50e995
--- /dev/null
+++ b/tests/ui/macros/macro-stmt-matchers.rs
@@ -0,0 +1,7 @@
+// build-pass (FIXME(62277): could be check-pass?)
+
+
+fn main() {
+    macro_rules! m { ($s:stmt;) => { $s } }
+    m!(vec![].push(0););
+}
diff --git a/tests/ui/macros/macro-stmt.rs b/tests/ui/macros/macro-stmt.rs
new file mode 100644
index 00000000000..c9a0b879a0f
--- /dev/null
+++ b/tests/ui/macros/macro-stmt.rs
@@ -0,0 +1,31 @@
+// run-pass
+macro_rules! myfn {
+    ( $f:ident, ( $( $x:ident ),* ), $body:block ) => (
+        fn $f( $( $x : isize),* ) -> isize $body
+    )
+}
+
+myfn!(add, (a,b), { return a+b; } );
+
+pub fn main() {
+
+    macro_rules! mylet {
+        ($x:ident, $val:expr) => (
+            let $x = $val;
+        )
+    }
+
+    mylet!(y, 8*2);
+    assert_eq!(y, 16);
+
+    myfn!(mult, (a,b), { a*b } );
+
+    assert_eq!(mult(2, add(4,4)), 16);
+
+    macro_rules! actually_an_expr_macro {
+        () => ( 16 )
+    }
+
+    assert_eq!({ actually_an_expr_macro!() }, 16);
+
+}
diff --git a/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs b/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs
new file mode 100644
index 00000000000..528d0b28bf6
--- /dev/null
+++ b/tests/ui/macros/macro-stmt_macro_in_expr_macro.rs
@@ -0,0 +1,21 @@
+// run-pass
+#![allow(dead_code)]
+macro_rules! foo {
+    () => {
+        struct Bar;
+        struct Baz;
+    }
+}
+
+macro_rules! grault {
+    () => {{
+        foo!();
+        struct Xyzzy;
+        0
+    }}
+}
+
+fn main() {
+    let x = grault!();
+    assert_eq!(x, 0);
+}
diff --git a/tests/ui/macros/macro-tt-followed-by-seq.rs b/tests/ui/macros/macro-tt-followed-by-seq.rs
new file mode 100644
index 00000000000..080dbcfdd41
--- /dev/null
+++ b/tests/ui/macros/macro-tt-followed-by-seq.rs
@@ -0,0 +1,28 @@
+// run-pass
+// Regression test for issue #25436: permit token-trees to be followed
+// by sequences, enabling more general parsing.
+
+use self::Join::*;
+
+#[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
+enum Join<A,B> {
+  Keep(A,B),
+  Skip(A,B),
+}
+
+macro_rules! parse_list {
+  ( < $a:expr; > $($b:tt)* ) => { Keep(parse_item!($a),parse_list!($($b)*)) };
+  ( $a:tt $($b:tt)* ) => { Skip(parse_item!($a), parse_list!($($b)*)) };
+  ( ) => { () };
+}
+
+macro_rules! parse_item {
+  ( $x:expr ) => { $x }
+}
+
+fn main() {
+    let list = parse_list!(<1;> 2 <3;> 4);
+    assert_eq!("Keep(1, Skip(2, Keep(3, Skip(4, ()))))",
+               format!("{:?}", list));
+}
diff --git a/tests/ui/macros/macro-tt-matchers.rs b/tests/ui/macros/macro-tt-matchers.rs
new file mode 100644
index 00000000000..2ee41b0880e
--- /dev/null
+++ b/tests/ui/macros/macro-tt-matchers.rs
@@ -0,0 +1,11 @@
+// build-pass (FIXME(62277): could be check-pass?)
+#![allow(dead_code)]
+
+macro_rules! foo {
+    ($x:tt) => (type Alias = $x<i32>;)
+}
+
+foo!(Box);
+
+
+fn main() {}
diff --git a/tests/ui/macros/macro-use-all-and-none.rs b/tests/ui/macros/macro-use-all-and-none.rs
new file mode 100644
index 00000000000..c8bd44008b0
--- /dev/null
+++ b/tests/ui/macros/macro-use-all-and-none.rs
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:two_macros-rpass.rs
+
+#![warn(unused_attributes)]
+
+#[macro_use]
+#[macro_use()] //~ WARNING unused attribute
+extern crate two_macros_rpass;
+
+pub fn main() {
+    macro_one!();
+    macro_two!();
+}
diff --git a/tests/ui/macros/macro-use-all-and-none.stderr b/tests/ui/macros/macro-use-all-and-none.stderr
new file mode 100644
index 00000000000..00b10dccd00
--- /dev/null
+++ b/tests/ui/macros/macro-use-all-and-none.stderr
@@ -0,0 +1,15 @@
+warning: unused attribute
+  --> $DIR/macro-use-all-and-none.rs:7:1
+   |
+LL | #[macro_use()]
+   | ^^^^^^^^^^^^^^ help: remove this attribute
+   |
+   = note: attribute `macro_use` with an empty list has no effect
+note: the lint level is defined here
+  --> $DIR/macro-use-all-and-none.rs:4:9
+   |
+LL | #![warn(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/macros/macro-use-all.rs b/tests/ui/macros/macro-use-all.rs
new file mode 100644
index 00000000000..48c7b77e579
--- /dev/null
+++ b/tests/ui/macros/macro-use-all.rs
@@ -0,0 +1,10 @@
+// run-pass
+// aux-build:two_macros.rs
+
+#[macro_use]
+extern crate two_macros;
+
+pub fn main() {
+    macro_one!();
+    macro_two!();
+}
diff --git a/tests/ui/macros/macro-use-bad-args-1.rs b/tests/ui/macros/macro-use-bad-args-1.rs
new file mode 100644
index 00000000000..ec0b64a1095
--- /dev/null
+++ b/tests/ui/macros/macro-use-bad-args-1.rs
@@ -0,0 +1,6 @@
+#![no_std]
+
+#[macro_use(foo(bar))]  //~ ERROR bad macro import
+extern crate std;
+
+fn main() {}
diff --git a/tests/ui/macros/macro-use-bad-args-1.stderr b/tests/ui/macros/macro-use-bad-args-1.stderr
new file mode 100644
index 00000000000..4e5482a518c
--- /dev/null
+++ b/tests/ui/macros/macro-use-bad-args-1.stderr
@@ -0,0 +1,9 @@
+error[E0466]: bad macro import
+  --> $DIR/macro-use-bad-args-1.rs:3:13
+   |
+LL | #[macro_use(foo(bar))]
+   |             ^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0466`.
diff --git a/tests/ui/macros/macro-use-bad-args-2.rs b/tests/ui/macros/macro-use-bad-args-2.rs
new file mode 100644
index 00000000000..c5f8f62c186
--- /dev/null
+++ b/tests/ui/macros/macro-use-bad-args-2.rs
@@ -0,0 +1,6 @@
+#![no_std]
+
+#[macro_use(foo="bar")]  //~ ERROR bad macro import
+extern crate std;
+
+fn main() {}
diff --git a/tests/ui/macros/macro-use-bad-args-2.stderr b/tests/ui/macros/macro-use-bad-args-2.stderr
new file mode 100644
index 00000000000..c958104eac4
--- /dev/null
+++ b/tests/ui/macros/macro-use-bad-args-2.stderr
@@ -0,0 +1,9 @@
+error[E0466]: bad macro import
+  --> $DIR/macro-use-bad-args-2.rs:3:13
+   |
+LL | #[macro_use(foo="bar")]
+   |             ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0466`.
diff --git a/tests/ui/macros/macro-use-both.rs b/tests/ui/macros/macro-use-both.rs
new file mode 100644
index 00000000000..ed5d1312f96
--- /dev/null
+++ b/tests/ui/macros/macro-use-both.rs
@@ -0,0 +1,10 @@
+// run-pass
+// aux-build:two_macros.rs
+
+#[macro_use(macro_one, macro_two)]
+extern crate two_macros;
+
+pub fn main() {
+    macro_one!();
+    macro_two!();
+}
diff --git a/tests/ui/macros/macro-use-one.rs b/tests/ui/macros/macro-use-one.rs
new file mode 100644
index 00000000000..f74795e68dc
--- /dev/null
+++ b/tests/ui/macros/macro-use-one.rs
@@ -0,0 +1,9 @@
+// run-pass
+// aux-build:two_macros.rs
+
+#[macro_use(macro_two)]
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}
diff --git a/tests/ui/macros/macro-use-scope.rs b/tests/ui/macros/macro-use-scope.rs
new file mode 100644
index 00000000000..5e58fc9c1ed
--- /dev/null
+++ b/tests/ui/macros/macro-use-scope.rs
@@ -0,0 +1,22 @@
+// aux-build:two_macros.rs
+
+// build-pass (FIXME(62277): could be check-pass?)
+#![allow(unused)]
+
+fn f() {
+    let _ = macro_one!();
+}
+#[macro_use(macro_one)] // Check that this macro is usable in the above function
+extern crate two_macros;
+
+fn g() {
+    macro_two!();
+}
+macro_rules! m { () => {
+    #[macro_use(macro_two)] // Check that this macro is usable in the above function
+    extern crate two_macros as _two_macros;
+} }
+m!();
+
+
+fn main() {}
diff --git a/tests/ui/macros/macro-use-undef.rs b/tests/ui/macros/macro-use-undef.rs
new file mode 100644
index 00000000000..ae3054e7b82
--- /dev/null
+++ b/tests/ui/macros/macro-use-undef.rs
@@ -0,0 +1,8 @@
+// aux-build:two_macros.rs
+
+#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}
diff --git a/tests/ui/macros/macro-use-undef.stderr b/tests/ui/macros/macro-use-undef.stderr
new file mode 100644
index 00000000000..85b86e2211f
--- /dev/null
+++ b/tests/ui/macros/macro-use-undef.stderr
@@ -0,0 +1,9 @@
+error[E0469]: imported macro not found
+  --> $DIR/macro-use-undef.rs:3:24
+   |
+LL | #[macro_use(macro_two, no_way)]
+   |                        ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0469`.
diff --git a/tests/ui/macros/macro-use-wrong-name.rs b/tests/ui/macros/macro-use-wrong-name.rs
new file mode 100644
index 00000000000..d142b580003
--- /dev/null
+++ b/tests/ui/macros/macro-use-wrong-name.rs
@@ -0,0 +1,9 @@
+// aux-build:two_macros.rs
+
+#[macro_use(macro_one)]
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+    //~^ ERROR cannot find macro
+}
diff --git a/tests/ui/macros/macro-use-wrong-name.stderr b/tests/ui/macros/macro-use-wrong-name.stderr
new file mode 100644
index 00000000000..326001fc15a
--- /dev/null
+++ b/tests/ui/macros/macro-use-wrong-name.stderr
@@ -0,0 +1,16 @@
+error: cannot find macro `macro_two` in this scope
+  --> $DIR/macro-use-wrong-name.rs:7:5
+   |
+LL |     macro_two!();
+   |     ^^^^^^^^^ help: a macro with a similar name exists: `macro_one`
+   |
+  ::: $DIR/auxiliary/two_macros.rs:2:1
+   |
+LL | macro_rules! macro_one { () => ("one") }
+   | ---------------------- similarly named macro `macro_one` defined here
+   |
+   = note: consider importing this macro:
+           two_macros::macro_two
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro-with-attrs1.rs b/tests/ui/macros/macro-with-attrs1.rs
new file mode 100644
index 00000000000..4e943b224cd
--- /dev/null
+++ b/tests/ui/macros/macro-with-attrs1.rs
@@ -0,0 +1,13 @@
+// run-pass
+// compile-flags: --cfg foo
+
+
+#[cfg(foo)]
+macro_rules! foo { () => (1) }
+
+#[cfg(not(foo))]
+macro_rules! foo { () => (2) }
+
+pub fn main() {
+    assert_eq!(foo!(), 1);
+}
diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs
new file mode 100644
index 00000000000..78c40810207
--- /dev/null
+++ b/tests/ui/macros/macro-with-attrs2.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+#[cfg(foo)]
+macro_rules! foo { () => (1) }
+
+#[cfg(not(foo))]
+macro_rules! foo { () => (2) }
+
+pub fn main() {
+    assert_eq!(foo!(), 2);
+}
diff --git a/tests/ui/macros/macro-with-braces-in-expr-position.rs b/tests/ui/macros/macro-with-braces-in-expr-position.rs
new file mode 100644
index 00000000000..f7d87434ded
--- /dev/null
+++ b/tests/ui/macros/macro-with-braces-in-expr-position.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![allow(unused_must_use)]
+// ignore-emscripten no threads support
+
+use std::thread;
+
+macro_rules! expr { ($e: expr) => { $e } }
+
+macro_rules! spawn {
+    ($($code: tt)*) => {
+        expr!(thread::spawn(move|| {$($code)*}).join())
+    }
+}
+
+pub fn main() {
+    spawn! {
+        println!("stmt");
+    };
+    let _ = spawn! {
+        println!("expr");
+    };
+}
diff --git a/tests/ui/macros/macro_path_as_generic_bound.rs b/tests/ui/macros/macro_path_as_generic_bound.rs
new file mode 100644
index 00000000000..663f85688ec
--- /dev/null
+++ b/tests/ui/macros/macro_path_as_generic_bound.rs
@@ -0,0 +1,9 @@
+trait Foo {}
+
+macro_rules! foo(($t:path) => {
+    impl<T: $t> Foo for T {}
+});
+
+foo!(m::m2::A); //~ ERROR failed to resolve
+
+fn main() {}
diff --git a/tests/ui/macros/macro_path_as_generic_bound.stderr b/tests/ui/macros/macro_path_as_generic_bound.stderr
new file mode 100644
index 00000000000..00d954d24f3
--- /dev/null
+++ b/tests/ui/macros/macro_path_as_generic_bound.stderr
@@ -0,0 +1,9 @@
+error[E0433]: failed to resolve: use of undeclared crate or module `m`
+  --> $DIR/macro_path_as_generic_bound.rs:7:6
+   |
+LL | foo!(m::m2::A);
+   |      ^ use of undeclared crate or module `m`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/macro_rules-unmatchable-literals.rs b/tests/ui/macros/macro_rules-unmatchable-literals.rs
new file mode 100644
index 00000000000..bde0fe1a015
--- /dev/null
+++ b/tests/ui/macros/macro_rules-unmatchable-literals.rs
@@ -0,0 +1,14 @@
+// Pinning tests for things that don't work to make sure we notice if that changes
+
+#![crate_type = "lib"]
+
+macro_rules! octal_with_bad_digit {
+    ( 0o1238 ) => {}; //~ ERROR invalid digit
+}
+
+macro_rules! binary_with_bad_digit {
+    ( 0b012 ) => {}; //~ ERROR invalid digit
+}
+
+// This can't happen for Hex and Decimal as things like `123A` and `0xFFG`
+// get treated as unknown *suffixes*, rather than digits.
diff --git a/tests/ui/macros/macro_rules-unmatchable-literals.stderr b/tests/ui/macros/macro_rules-unmatchable-literals.stderr
new file mode 100644
index 00000000000..956a669791d
--- /dev/null
+++ b/tests/ui/macros/macro_rules-unmatchable-literals.stderr
@@ -0,0 +1,14 @@
+error: invalid digit for a base 8 literal
+  --> $DIR/macro_rules-unmatchable-literals.rs:6:12
+   |
+LL |     ( 0o1238 ) => {};
+   |            ^
+
+error: invalid digit for a base 2 literal
+  --> $DIR/macro_rules-unmatchable-literals.rs:10:11
+   |
+LL |     ( 0b012 ) => {};
+   |           ^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro_undefined.rs b/tests/ui/macros/macro_undefined.rs
new file mode 100644
index 00000000000..6ca1eb56861
--- /dev/null
+++ b/tests/ui/macros/macro_undefined.rs
@@ -0,0 +1,13 @@
+// Test macro_undefined issue
+
+mod m {
+    #[macro_export]
+    macro_rules! kl {
+        () => ()
+    }
+}
+
+fn main() {
+    k!(); //~ ERROR cannot find
+    kl!();
+}
diff --git a/tests/ui/macros/macro_undefined.stderr b/tests/ui/macros/macro_undefined.stderr
new file mode 100644
index 00000000000..4ab16bd1017
--- /dev/null
+++ b/tests/ui/macros/macro_undefined.stderr
@@ -0,0 +1,11 @@
+error: cannot find macro `k` in this scope
+  --> $DIR/macro_undefined.rs:11:5
+   |
+LL |     macro_rules! kl {
+   |     --------------- similarly named macro `kl` defined here
+...
+LL |     k!();
+   |     ^ help: a macro with a similar name exists: `kl`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/macro_with_super_2.rs b/tests/ui/macros/macro_with_super_2.rs
new file mode 100644
index 00000000000..2901a74f612
--- /dev/null
+++ b/tests/ui/macros/macro_with_super_2.rs
@@ -0,0 +1,13 @@
+// run-pass
+// aux-build:macro_with_super_1.rs
+
+// pretty-expanded FIXME #23616
+
+#[macro_use]
+extern crate macro_with_super_1;
+
+declare!();
+
+fn main() {
+    bbb::ccc();
+}
diff --git a/tests/ui/macros/macros-in-extern.rs b/tests/ui/macros/macros-in-extern.rs
new file mode 100644
index 00000000000..568ae3a8539
--- /dev/null
+++ b/tests/ui/macros/macros-in-extern.rs
@@ -0,0 +1,51 @@
+// run-pass
+// ignore-wasm32
+
+#![feature(decl_macro)]
+
+macro_rules! returns_isize(
+    ($ident:ident) => (
+        fn $ident() -> isize;
+    )
+);
+
+macro takes_u32_returns_u32($ident:ident) {
+    fn $ident(arg: u32) -> u32;
+}
+
+macro_rules! emits_nothing(
+    () => ()
+);
+
+macro_rules! emits_multiple(
+    () => {
+        fn f1() -> u32;
+        fn f2() -> u32;
+    }
+);
+
+mod defs {
+    #[no_mangle]
+    extern "C" fn f1() -> u32 {
+        1
+    }
+    #[no_mangle]
+    extern "C" fn f2() -> u32 {
+        2
+    }
+}
+
+fn main() {
+    assert_eq!(unsafe { rust_get_test_int() }, 1);
+    assert_eq!(unsafe { rust_dbg_extern_identity_u32(0xDEADBEEF) }, 0xDEADBEEFu32);
+    assert_eq!(unsafe { f1() }, 1);
+    assert_eq!(unsafe { f2() }, 2);
+}
+
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    returns_isize!(rust_get_test_int);
+    takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
+    emits_nothing!();
+    emits_multiple!();
+}
diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs
new file mode 100644
index 00000000000..ab14c35893d
--- /dev/null
+++ b/tests/ui/macros/macros-nonfatal-errors.rs
@@ -0,0 +1,139 @@
+// normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG ("
+
+// test that errors in a (selection) of macros don't kill compilation
+// immediately, so that we get more errors listed at a time.
+
+#![feature(trace_macros, concat_idents)]
+#![feature(stmt_expr_attributes)]
+
+use std::arch::asm;
+
+#[derive(Default)]
+struct DefaultInnerAttrStruct {
+    #[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+    foo: (),
+}
+
+#[derive(Default)]
+struct DefaultInnerAttrTupleStruct(#[default] ());
+//~^ ERROR the `#[default]` attribute may only be used on unit enum variants
+
+#[derive(Default)]
+#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+struct DefaultOuterAttrStruct {}
+
+#[derive(Default)]
+#[default] //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+enum DefaultOuterAttrEnum {
+    #[default]
+    Foo,
+}
+
+#[rustfmt::skip] // needs some work to handle this case
+#[repr(u8)]
+#[derive(Default)]
+enum AttrOnInnerExpression {
+    Foo = #[default] 0, //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+    Bar([u8; #[default] 1]), //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+    #[default]
+    Baz,
+}
+
+#[derive(Default)] //~ ERROR no default declared
+enum NoDeclaredDefault {
+    Foo,
+    Bar,
+}
+
+#[derive(Default)] //~ ERROR multiple declared defaults
+enum MultipleDefaults {
+    #[default]
+    Foo,
+    #[default]
+    Bar,
+    #[default]
+    Baz,
+}
+
+#[derive(Default)]
+enum ExtraDeriveTokens {
+    #[default = 1] //~ ERROR `#[default]` attribute does not accept a value
+    Foo,
+}
+
+#[derive(Default)]
+enum TwoDefaultAttrs {
+    #[default]
+    #[default]
+    Foo, //~ERROR multiple `#[default]` attributes
+    Bar,
+}
+
+#[derive(Default)]
+enum ManyDefaultAttrs {
+    #[default]
+    #[default]
+    #[default]
+    #[default]
+    Foo, //~ERROR multiple `#[default]` attributes
+    Bar,
+}
+
+#[derive(Default)]
+enum DefaultHasFields {
+    #[default]
+    Foo {}, //~ ERROR the `#[default]` attribute may only be used on unit enum variants
+    Bar,
+}
+
+#[derive(Default)]
+enum NonExhaustiveDefault {
+    #[default]
+    #[non_exhaustive]
+    Foo, //~ ERROR default variant must be exhaustive
+    Bar,
+}
+
+fn main() {
+    asm!(invalid); //~ ERROR
+    llvm_asm!(invalid); //~ ERROR
+
+    concat_idents!("not", "idents"); //~ ERROR
+
+    option_env!(invalid); //~ ERROR
+    env!(invalid); //~ ERROR
+    env!(foo, abr, baz); //~ ERROR
+    env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); //~ ERROR
+
+    format!(invalid); //~ ERROR
+
+    include!(invalid); //~ ERROR
+
+    include_str!(invalid); //~ ERROR
+    include_str!("i'd be quite surprised if a file with this name existed"); //~ ERROR
+    include_bytes!(invalid); //~ ERROR
+    include_bytes!("i'd be quite surprised if a file with this name existed"); //~ ERROR
+
+    trace_macros!(invalid); //~ ERROR
+}
+
+/// Check that `#[derive(Default)]` does use a `T : Default` bound when the
+/// `#[default]` variant is `#[non_exhaustive]` (should this end up allowed).
+const _: () = {
+    #[derive(Default)]
+    enum NonExhaustiveDefaultGeneric<T> {
+        #[default]
+        #[non_exhaustive]
+        Foo, //~ ERROR default variant must be exhaustive
+        Bar(T),
+    }
+
+    fn assert_impls_default<T: Default>() {}
+
+    enum NotDefault {}
+
+    // Note: the `derive(Default)` currently bails early enough for trait-checking
+    // not to happen. Should it bail late enough, or even pass, make sure to
+    // assert that the following line fails.
+    let _ = assert_impls_default::<NonExhaustiveDefaultGeneric<NotDefault>>;
+};
diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr
new file mode 100644
index 00000000000..d42f6c179b7
--- /dev/null
+++ b/tests/ui/macros/macros-nonfatal-errors.stderr
@@ -0,0 +1,235 @@
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:13:5
+   |
+LL |     #[default]
+   |     ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:18:36
+   |
+LL | struct DefaultInnerAttrTupleStruct(#[default] ());
+   |                                    ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:22:1
+   |
+LL | #[default]
+   | ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:26:1
+   |
+LL | #[default]
+   | ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:36:11
+   |
+LL |     Foo = #[default] 0,
+   |           ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:37:14
+   |
+LL |     Bar([u8; #[default] 1]),
+   |              ^^^^^^^^^^
+
+error: no default declared
+  --> $DIR/macros-nonfatal-errors.rs:42:10
+   |
+LL | #[derive(Default)]
+   |          ^^^^^^^
+   |
+   = help: make a unit variant default by placing `#[default]` above it
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: multiple declared defaults
+  --> $DIR/macros-nonfatal-errors.rs:48:10
+   |
+LL | #[derive(Default)]
+   |          ^^^^^^^
+...
+LL |     Foo,
+   |     --- first default
+LL |     #[default]
+LL |     Bar,
+   |     --- additional default
+LL |     #[default]
+LL |     Baz,
+   |     --- additional default
+   |
+   = note: only one variant can be default
+   = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `#[default]` attribute does not accept a value
+  --> $DIR/macros-nonfatal-errors.rs:60:5
+   |
+LL |     #[default = 1]
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: try using `#[default]`
+
+error: multiple `#[default]` attributes
+  --> $DIR/macros-nonfatal-errors.rs:68:5
+   |
+LL |     #[default]
+   |     ---------- `#[default]` used here
+LL |     #[default]
+   |     ---------- `#[default]` used again here
+LL |     Foo,
+   |     ^^^
+   |
+   = note: only one `#[default]` attribute is needed
+help: try removing this
+  --> $DIR/macros-nonfatal-errors.rs:67:5
+   |
+LL |     #[default]
+   |     ^^^^^^^^^^
+
+error: multiple `#[default]` attributes
+  --> $DIR/macros-nonfatal-errors.rs:78:5
+   |
+LL |     #[default]
+   |     ---------- `#[default]` used here
+LL |     #[default]
+   |     ---------- `#[default]` used again here
+...
+LL |     Foo,
+   |     ^^^
+   |
+   = note: only one `#[default]` attribute is needed
+help: try removing these
+  --> $DIR/macros-nonfatal-errors.rs:75:5
+   |
+LL |     #[default]
+   |     ^^^^^^^^^^
+LL |     #[default]
+   |     ^^^^^^^^^^
+LL |     #[default]
+   |     ^^^^^^^^^^
+
+error: the `#[default]` attribute may only be used on unit enum variants
+  --> $DIR/macros-nonfatal-errors.rs:85:5
+   |
+LL |     Foo {},
+   |     ^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error: default variant must be exhaustive
+  --> $DIR/macros-nonfatal-errors.rs:93:5
+   |
+LL |     #[non_exhaustive]
+   |     ----------------- declared `#[non_exhaustive]` here
+LL |     Foo,
+   |     ^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error: asm template must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:98:10
+   |
+LL |     asm!(invalid);
+   |          ^^^^^^^
+
+error: concat_idents! requires ident args
+  --> $DIR/macros-nonfatal-errors.rs:101:5
+   |
+LL |     concat_idents!("not", "idents");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: argument must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:103:17
+   |
+LL |     option_env!(invalid);
+   |                 ^^^^^^^
+
+error: expected string literal
+  --> $DIR/macros-nonfatal-errors.rs:104:10
+   |
+LL |     env!(invalid);
+   |          ^^^^^^^
+
+error: expected string literal
+  --> $DIR/macros-nonfatal-errors.rs:105:10
+   |
+LL |     env!(foo, abr, baz);
+   |          ^^^
+
+error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
+  --> $DIR/macros-nonfatal-errors.rs:106:5
+   |
+LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: format argument must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:108:13
+   |
+LL |     format!(invalid);
+   |             ^^^^^^^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     format!("{}", invalid);
+   |             +++++
+
+error: argument must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:110:14
+   |
+LL |     include!(invalid);
+   |              ^^^^^^^
+
+error: argument must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:112:18
+   |
+LL |     include_str!(invalid);
+   |                  ^^^^^^^
+
+error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/macros-nonfatal-errors.rs:113:5
+   |
+LL |     include_str!("i'd be quite surprised if a file with this name existed");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: argument must be a string literal
+  --> $DIR/macros-nonfatal-errors.rs:114:20
+   |
+LL |     include_bytes!(invalid);
+   |                    ^^^^^^^
+
+error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
+  --> $DIR/macros-nonfatal-errors.rs:115:5
+   |
+LL |     include_bytes!("i'd be quite surprised if a file with this name existed");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/macros-nonfatal-errors.rs:117:5
+   |
+LL |     trace_macros!(invalid);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: default variant must be exhaustive
+  --> $DIR/macros-nonfatal-errors.rs:127:9
+   |
+LL |         #[non_exhaustive]
+   |         ----------------- declared `#[non_exhaustive]` here
+LL |         Foo,
+   |         ^^^
+   |
+   = help: consider a manual implementation of `Default`
+
+error: cannot find macro `llvm_asm` in this scope
+  --> $DIR/macros-nonfatal-errors.rs:99:5
+   |
+LL |     llvm_asm!(invalid);
+   |     ^^^^^^^^
+
+error: aborting due to 28 previous errors
+
diff --git a/tests/ui/macros/malformed_macro_lhs.rs b/tests/ui/macros/malformed_macro_lhs.rs
new file mode 100644
index 00000000000..f57d2fb4dc9
--- /dev/null
+++ b/tests/ui/macros/malformed_macro_lhs.rs
@@ -0,0 +1,7 @@
+macro_rules! my_precioooous {
+    t => (1); //~ ERROR invalid macro matcher
+}
+
+fn main() {
+    my_precioooous!();
+}
diff --git a/tests/ui/macros/malformed_macro_lhs.stderr b/tests/ui/macros/malformed_macro_lhs.stderr
new file mode 100644
index 00000000000..adf64b08935
--- /dev/null
+++ b/tests/ui/macros/malformed_macro_lhs.stderr
@@ -0,0 +1,8 @@
+error: invalid macro matcher; matchers must be contained in balanced delimiters
+  --> $DIR/malformed_macro_lhs.rs:2:5
+   |
+LL |     t => (1);
+   |     ^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/meta-item-absolute-path.rs b/tests/ui/macros/meta-item-absolute-path.rs
new file mode 100644
index 00000000000..8ed911cbca7
--- /dev/null
+++ b/tests/ui/macros/meta-item-absolute-path.rs
@@ -0,0 +1,5 @@
+#[derive(::Absolute)] //~ ERROR failed to resolve
+                      //~| ERROR failed to resolve
+struct S;
+
+fn main() {}
diff --git a/tests/ui/macros/meta-item-absolute-path.stderr b/tests/ui/macros/meta-item-absolute-path.stderr
new file mode 100644
index 00000000000..c53971e245f
--- /dev/null
+++ b/tests/ui/macros/meta-item-absolute-path.stderr
@@ -0,0 +1,15 @@
+error[E0433]: failed to resolve: maybe a missing crate `Absolute`?
+  --> $DIR/meta-item-absolute-path.rs:1:12
+   |
+LL | #[derive(::Absolute)]
+   |            ^^^^^^^^ maybe a missing crate `Absolute`?
+
+error[E0433]: failed to resolve: maybe a missing crate `Absolute`?
+  --> $DIR/meta-item-absolute-path.rs:1:12
+   |
+LL | #[derive(::Absolute)]
+   |            ^^^^^^^^ maybe a missing crate `Absolute`?
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.rs b/tests/ui/macros/meta-variable-depth-outside-repeat.rs
new file mode 100644
index 00000000000..b7fb947854f
--- /dev/null
+++ b/tests/ui/macros/meta-variable-depth-outside-repeat.rs
@@ -0,0 +1,12 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! metavar {
+    ( $i:expr ) => {
+        ${length(0)}
+        //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+    };
+}
+
+const _: i32 = metavar!(0);
+
+fn main() {}
diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.stderr b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr
new file mode 100644
index 00000000000..fad150cadfc
--- /dev/null
+++ b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr
@@ -0,0 +1,8 @@
+error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+  --> $DIR/meta-variable-depth-outside-repeat.rs:5:10
+   |
+LL |         ${length(0)}
+   |          ^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/meta-variable-misuse.rs b/tests/ui/macros/meta-variable-misuse.rs
new file mode 100644
index 00000000000..99a2f940176
--- /dev/null
+++ b/tests/ui/macros/meta-variable-misuse.rs
@@ -0,0 +1,34 @@
+// run-pass
+#![deny(meta_variable_misuse)]
+
+macro_rules! foo {
+    ($($m:ident $($f:ident $v:tt)+),*) => {
+        $($(macro_rules! $f { () => { $v } })+)*
+        $(macro_rules! $m { () => { $(fn $f() -> i32 { $v })+ } })*
+    }
+}
+
+foo!(m a 1 b 2, n c 3);
+m!();
+n!();
+
+macro_rules! no_shadow {
+    ($x:tt) => { macro_rules! bar { ($x:tt) => { 42 }; } };
+}
+no_shadow!(z);
+
+macro_rules! make_plus {
+    ($n: ident $x:expr) => { macro_rules! $n { ($y:expr) => { $x + $y }; } };
+}
+make_plus!(add3 3);
+
+fn main() {
+    assert_eq!(a!(), 1);
+    assert_eq!(b!(), 2);
+    assert_eq!(c!(), 3);
+    assert_eq!(a(), 1);
+    assert_eq!(b(), 2);
+    assert_eq!(c(), 3);
+    assert_eq!(bar!(z:tt), 42);
+    assert_eq!(add3!(9), 12);
+}
diff --git a/tests/ui/macros/missing-bang-in-decl.fixed b/tests/ui/macros/missing-bang-in-decl.fixed
new file mode 100644
index 00000000000..b1aa3298bfa
--- /dev/null
+++ b/tests/ui/macros/missing-bang-in-decl.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules! foo {
+    //~^ ERROR expected `!` after `macro_rules`
+    () => {};
+}
+
+macro_rules! bar {
+    //~^ ERROR expected `!` after `macro_rules`
+    //~^^ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-bang-in-decl.rs b/tests/ui/macros/missing-bang-in-decl.rs
new file mode 100644
index 00000000000..8393f15fc52
--- /dev/null
+++ b/tests/ui/macros/missing-bang-in-decl.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules foo {
+    //~^ ERROR expected `!` after `macro_rules`
+    () => {};
+}
+
+macro_rules bar! {
+    //~^ ERROR expected `!` after `macro_rules`
+    //~^^ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-bang-in-decl.stderr b/tests/ui/macros/missing-bang-in-decl.stderr
new file mode 100644
index 00000000000..dfabafb0a7a
--- /dev/null
+++ b/tests/ui/macros/missing-bang-in-decl.stderr
@@ -0,0 +1,20 @@
+error: expected `!` after `macro_rules`
+  --> $DIR/missing-bang-in-decl.rs:5:1
+   |
+LL | macro_rules foo {
+   | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: expected `!` after `macro_rules`
+  --> $DIR/missing-bang-in-decl.rs:10:1
+   |
+LL | macro_rules bar! {
+   | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: macro names aren't followed by a `!`
+  --> $DIR/missing-bang-in-decl.rs:10:16
+   |
+LL | macro_rules bar! {
+   |                ^ help: remove the `!`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs
new file mode 100644
index 00000000000..92f8a779505
--- /dev/null
+++ b/tests/ui/macros/missing-comma.rs
@@ -0,0 +1,34 @@
+macro_rules! foo {
+    ($a:ident) => ();
+    ($a:ident, $b:ident) => ();
+    ($a:ident, $b:ident, $c:ident) => ();
+    ($a:ident, $b:ident, $c:ident, $d:ident) => ();
+    ($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => ();
+}
+
+macro_rules! bar {
+    ($lvl:expr, $($arg:tt)+) => {}
+}
+
+macro_rules! check {
+    ($ty:ty, $expected:expr) => {};
+    ($ty_of:expr, $expected:expr) => {};
+}
+
+fn main() {
+    println!("{}" a);
+    //~^ ERROR expected `,`, found `a`
+    foo!(a b);
+    //~^ ERROR no rules expected the token `b`
+    foo!(a, b, c, d e);
+    //~^ ERROR no rules expected the token `e`
+    foo!(a, b, c d, e);
+    //~^ ERROR no rules expected the token `d`
+    foo!(a, b, c d e);
+    //~^ ERROR no rules expected the token `d`
+    bar!(Level::Error, );
+    //~^ ERROR unexpected end of macro invocation
+    check!(<str as Debug>::fmt, "fmt");
+    check!(<str as Debug>::fmt, "fmt",);
+    //~^ ERROR no rules expected the token `,`
+}
diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr
new file mode 100644
index 00000000000..81877a29ed8
--- /dev/null
+++ b/tests/ui/macros/missing-comma.stderr
@@ -0,0 +1,104 @@
+error: expected `,`, found `a`
+  --> $DIR/missing-comma.rs:19:19
+   |
+LL |     println!("{}" a);
+   |                   ^ expected `,`
+
+error: no rules expected the token `b`
+  --> $DIR/missing-comma.rs:21:12
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a b);
+   |           -^ no rules expected this token in macro call
+   |           |
+   |           help: missing comma here
+   |
+note: while trying to match meta-variable `$a:ident`
+  --> $DIR/missing-comma.rs:2:6
+   |
+LL |     ($a:ident) => ();
+   |      ^^^^^^^^
+
+error: no rules expected the token `e`
+  --> $DIR/missing-comma.rs:23:21
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a, b, c, d e);
+   |                    -^ no rules expected this token in macro call
+   |                    |
+   |                    help: missing comma here
+   |
+note: while trying to match meta-variable `$d:ident`
+  --> $DIR/missing-comma.rs:5:36
+   |
+LL |     ($a:ident, $b:ident, $c:ident, $d:ident) => ();
+   |                                    ^^^^^^^^
+
+error: no rules expected the token `d`
+  --> $DIR/missing-comma.rs:25:18
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a, b, c d, e);
+   |                 -^ no rules expected this token in macro call
+   |                 |
+   |                 help: missing comma here
+   |
+note: while trying to match meta-variable `$c:ident`
+  --> $DIR/missing-comma.rs:4:26
+   |
+LL |     ($a:ident, $b:ident, $c:ident) => ();
+   |                          ^^^^^^^^
+
+error: no rules expected the token `d`
+  --> $DIR/missing-comma.rs:27:18
+   |
+LL | macro_rules! foo {
+   | ---------------- when calling this macro
+...
+LL |     foo!(a, b, c d e);
+   |                  ^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$c:ident`
+  --> $DIR/missing-comma.rs:4:26
+   |
+LL |     ($a:ident, $b:ident, $c:ident) => ();
+   |                          ^^^^^^^^
+
+error: unexpected end of macro invocation
+  --> $DIR/missing-comma.rs:29:23
+   |
+LL | macro_rules! bar {
+   | ---------------- when calling this macro
+...
+LL |     bar!(Level::Error, );
+   |                       ^ missing tokens in macro arguments
+   |
+note: while trying to match meta-variable `$arg:tt`
+  --> $DIR/missing-comma.rs:10:19
+   |
+LL |     ($lvl:expr, $($arg:tt)+) => {}
+   |                   ^^^^^^^
+
+error: no rules expected the token `,`
+  --> $DIR/missing-comma.rs:32:38
+   |
+LL | macro_rules! check {
+   | ------------------ when calling this macro
+...
+LL |     check!(<str as Debug>::fmt, "fmt",);
+   |                                      ^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$expected:expr`
+  --> $DIR/missing-comma.rs:14:14
+   |
+LL |     ($ty:ty, $expected:expr) => {};
+   |              ^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/macros/must-use-in-macro-55516.rs b/tests/ui/macros/must-use-in-macro-55516.rs
new file mode 100644
index 00000000000..e7c3462867b
--- /dev/null
+++ b/tests/ui/macros/must-use-in-macro-55516.rs
@@ -0,0 +1,10 @@
+// check-pass
+// compile-flags: -Wunused
+
+// make sure write!() can't hide its unused Result
+
+fn main() {
+    use std::fmt::Write;
+    let mut example = String::new();
+    write!(&mut example, "{}", 42); //~WARN must be used
+}
diff --git a/tests/ui/macros/must-use-in-macro-55516.stderr b/tests/ui/macros/must-use-in-macro-55516.stderr
new file mode 100644
index 00000000000..8878b0eea0f
--- /dev/null
+++ b/tests/ui/macros/must-use-in-macro-55516.stderr
@@ -0,0 +1,12 @@
+warning: unused `Result` that must be used
+  --> $DIR/must-use-in-macro-55516.rs:9:5
+   |
+LL |     write!(&mut example, "{}", 42);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this `Result` may be an `Err` variant, which should be handled
+   = note: `-W unused-must-use` implied by `-W unused`
+   = note: this warning originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/macros/no-std-macros.rs b/tests/ui/macros/no-std-macros.rs
new file mode 100644
index 00000000000..ada643c7ac0
--- /dev/null
+++ b/tests/ui/macros/no-std-macros.rs
@@ -0,0 +1,13 @@
+// compile-flags: --crate-type=lib
+// check-pass
+// issue #55482
+#![no_std]
+
+macro_rules! foo {
+    ($e:expr) => {
+        $crate::core::assert!($e);
+        $crate::core::assert_eq!($e, true);
+    };
+}
+
+pub fn foo() { foo!(true); }
diff --git a/tests/ui/macros/none-delim-lookahead.rs b/tests/ui/macros/none-delim-lookahead.rs
new file mode 100644
index 00000000000..bf4fddea14b
--- /dev/null
+++ b/tests/ui/macros/none-delim-lookahead.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+macro_rules! make_struct {
+    ($name:ident) => {
+        #[derive(Debug)]
+        struct Foo {
+            #[cfg(not(FALSE))]
+            field: fn($name: bool)
+        }
+    }
+}
+
+make_struct!(param_name);
+
+fn main() {}
diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs
new file mode 100644
index 00000000000..84fffe44d6a
--- /dev/null
+++ b/tests/ui/macros/nonterminal-matching.rs
@@ -0,0 +1,26 @@
+// Check that we are refusing to match on complex nonterminals for which tokens are
+// unavailable and we'd have to go through AST comparisons.
+
+#![feature(decl_macro)]
+
+macro simple_nonterminal($nt_ident: ident, $nt_lifetime: lifetime, $nt_tt: tt) {
+    macro n(a $nt_ident b $nt_lifetime c $nt_tt d) {
+        struct S;
+    }
+
+    n!(a $nt_ident b $nt_lifetime c $nt_tt d);
+}
+
+macro complex_nonterminal($nt_item: item) {
+    macro n(a $nt_item b) {
+        struct S;
+    }
+
+    n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}`
+}
+
+simple_nonterminal!(a, 'a, (x, y, z)); // OK
+
+complex_nonterminal!(enum E {});
+
+fn main() {}
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
new file mode 100644
index 00000000000..5bbd5439098
--- /dev/null
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -0,0 +1,24 @@
+error: no rules expected the token `enum E {}`
+  --> $DIR/nonterminal-matching.rs:19:10
+   |
+LL |     macro n(a $nt_item b) {
+   |     --------------------- when calling this macro
+...
+LL |     n!(a $nt_item b);
+   |          ^^^^^^^^ no rules expected this token in macro call
+...
+LL | complex_nonterminal!(enum E {});
+   | ------------------------------- in this macro invocation
+   |
+note: while trying to match `enum E {}`
+  --> $DIR/nonterminal-matching.rs:15:15
+   |
+LL |     macro n(a $nt_item b) {
+   |               ^^^^^^^^
+...
+LL | complex_nonterminal!(enum E {});
+   | ------------------------------- in this macro invocation
+   = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/not-utf8.bin b/tests/ui/macros/not-utf8.bin
new file mode 100644
index 00000000000..4148e5b88fe
--- /dev/null
+++ b/tests/ui/macros/not-utf8.bin
Binary files differdiff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs
new file mode 100644
index 00000000000..1cb1fdcb8c9
--- /dev/null
+++ b/tests/ui/macros/not-utf8.rs
@@ -0,0 +1,5 @@
+// error-pattern: did not contain valid UTF-8
+
+fn foo() {
+    include!("not-utf8.bin")
+}
diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr
new file mode 100644
index 00000000000..7e1f2dcad11
--- /dev/null
+++ b/tests/ui/macros/not-utf8.stderr
@@ -0,0 +1,10 @@
+error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8
+  --> $DIR/not-utf8.rs:4:5
+   |
+LL |     include!("not-utf8.bin")
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/out-of-order-shadowing.rs b/tests/ui/macros/out-of-order-shadowing.rs
new file mode 100644
index 00000000000..a0d1a973764
--- /dev/null
+++ b/tests/ui/macros/out-of-order-shadowing.rs
@@ -0,0 +1,10 @@
+// aux-build:define-macro.rs
+
+macro_rules! bar { () => {} }
+define_macro!(bar);
+bar!(); //~ ERROR `bar` is ambiguous
+
+macro_rules! m { () => { #[macro_use] extern crate define_macro; } }
+m!();
+
+fn main() {}
diff --git a/tests/ui/macros/out-of-order-shadowing.stderr b/tests/ui/macros/out-of-order-shadowing.stderr
new file mode 100644
index 00000000000..dedefac5c46
--- /dev/null
+++ b/tests/ui/macros/out-of-order-shadowing.stderr
@@ -0,0 +1,22 @@
+error[E0659]: `bar` is ambiguous
+  --> $DIR/out-of-order-shadowing.rs:5:1
+   |
+LL | bar!();
+   | ^^^ ambiguous name
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `bar` could refer to the macro defined here
+  --> $DIR/out-of-order-shadowing.rs:4:1
+   |
+LL | define_macro!(bar);
+   | ^^^^^^^^^^^^^^^^^^
+note: `bar` could also refer to the macro defined here
+  --> $DIR/out-of-order-shadowing.rs:3:1
+   |
+LL | macro_rules! bar { () => {} }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `define_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs
new file mode 100644
index 00000000000..8fef9b0ed87
--- /dev/null
+++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![allow(stable_features)]
+
+// Test parsing binary operators after macro invocations.
+
+// pretty-expanded FIXME #23616
+
+#![feature(macro_rules)]
+
+macro_rules! id {
+    ($e: expr) => { $e }
+}
+
+fn foo() {
+    id!(1) + 1;
+    id![1] - 1;
+    id!(1) * 1;
+    id![1] / 1;
+    id!(1) % 1;
+
+    id!(1) & 1;
+    id![1] | 1;
+    id!(1) ^ 1;
+
+    let mut x = 1;
+    id![x] = 2;
+    id!(x) += 1;
+
+    id!(1f64).clone();
+
+    id!([1, 2, 3])[1];
+    id![drop](1);
+
+    id!(true) && true;
+    id![true] || true;
+}
+
+fn main() {}
diff --git a/tests/ui/macros/paths-in-macro-invocations.rs b/tests/ui/macros/paths-in-macro-invocations.rs
new file mode 100644
index 00000000000..622818a926f
--- /dev/null
+++ b/tests/ui/macros/paths-in-macro-invocations.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![allow(dead_code)]
+// aux-build:two_macros-rpass.rs
+
+extern crate two_macros_rpass as two_macros;
+
+::two_macros::macro_one!();
+two_macros::macro_one!();
+
+mod foo { pub use two_macros::macro_one as bar; }
+
+trait T {
+    foo::bar!();
+    ::foo::bar!();
+}
+
+struct S {
+    x: foo::bar!(i32),
+    y: ::foo::bar!(i32),
+}
+
+impl S {
+    foo::bar!();
+    ::foo::bar!();
+}
+
+fn main() {
+    foo::bar!();
+    ::foo::bar!();
+
+    let _ = foo::bar!(0);
+    let _ = ::foo::bar!(0);
+
+    let foo::bar!(_) = 0;
+    let ::foo::bar!(_) = 0;
+}
diff --git a/tests/ui/macros/proc_macro.rs b/tests/ui/macros/proc_macro.rs
new file mode 100644
index 00000000000..66f9cdc5567
--- /dev/null
+++ b/tests/ui/macros/proc_macro.rs
@@ -0,0 +1,37 @@
+// run-pass
+// aux-build:proc_macro_def.rs
+// ignore-cross-compile
+
+extern crate proc_macro_def;
+
+use proc_macro_def::{attr_tru, attr_identity, identity, ret_tru, tru};
+
+#[attr_tru]
+fn f1() -> bool {
+    return false;
+}
+
+#[attr_identity]
+fn f2() -> bool {
+    return identity!(true);
+}
+
+fn f3() -> identity!(bool) {
+    ret_tru!();
+}
+
+fn f4(x: bool) -> bool {
+    match x {
+        identity!(true) => false,
+        identity!(false) => true,
+    }
+}
+
+fn main() {
+    assert!(f1());
+    assert!(f2());
+    assert!(tru!());
+    assert!(f3());
+    assert!(identity!(5 == 5));
+    assert!(f4(false));
+}
diff --git a/tests/ui/macros/pub-item-inside-macro.rs b/tests/ui/macros/pub-item-inside-macro.rs
new file mode 100644
index 00000000000..d07681453a2
--- /dev/null
+++ b/tests/ui/macros/pub-item-inside-macro.rs
@@ -0,0 +1,18 @@
+// run-pass
+// Issue #14660
+
+// pretty-expanded FIXME #23616
+
+mod bleh {
+    macro_rules! foo {
+        () => {
+            pub fn bar() { }
+        }
+    }
+
+    foo!();
+}
+
+fn main() {
+    bleh::bar();
+}
diff --git a/tests/ui/macros/pub-method-inside-macro.rs b/tests/ui/macros/pub-method-inside-macro.rs
new file mode 100644
index 00000000000..bc918c7a4dc
--- /dev/null
+++ b/tests/ui/macros/pub-method-inside-macro.rs
@@ -0,0 +1,22 @@
+// run-pass
+// Issue #17436
+
+// pretty-expanded FIXME #23616
+
+mod bleh {
+    macro_rules! foo {
+        () => {
+            pub fn bar(&self) { }
+        }
+    }
+
+    pub struct S;
+
+    impl S {
+        foo!();
+    }
+}
+
+fn main() {
+    bleh::S.bar();
+}
diff --git a/tests/ui/macros/recovery-allowed.rs b/tests/ui/macros/recovery-allowed.rs
new file mode 100644
index 00000000000..ebf65f1cc01
--- /dev/null
+++ b/tests/ui/macros/recovery-allowed.rs
@@ -0,0 +1,8 @@
+macro_rules! please_recover {
+    ($a:expr) => {};
+}
+
+please_recover! { not 1 }
+//~^ ERROR unexpected `1` after identifier
+
+fn main() {}
diff --git a/tests/ui/macros/recovery-allowed.stderr b/tests/ui/macros/recovery-allowed.stderr
new file mode 100644
index 00000000000..ec036e8b1e2
--- /dev/null
+++ b/tests/ui/macros/recovery-allowed.stderr
@@ -0,0 +1,10 @@
+error: unexpected `1` after identifier
+  --> $DIR/recovery-allowed.rs:5:23
+   |
+LL | please_recover! { not 1 }
+   |                   ----^
+   |                   |
+   |                   help: use `!` to perform bitwise not
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/recovery-forbidden.rs b/tests/ui/macros/recovery-forbidden.rs
new file mode 100644
index 00000000000..5dd2619330c
--- /dev/null
+++ b/tests/ui/macros/recovery-forbidden.rs
@@ -0,0 +1,13 @@
+// check-pass
+
+macro_rules! dont_recover_here {
+    ($e:expr) => {
+        compile_error!("Must not recover to single !1 expr");
+    };
+
+    (not $a:literal) => {};
+}
+
+dont_recover_here! { not 1 }
+
+fn main() {}
diff --git a/tests/ui/macros/restricted-shadowing-legacy.rs b/tests/ui/macros/restricted-shadowing-legacy.rs
new file mode 100644
index 00000000000..f5cac2dfbfb
--- /dev/null
+++ b/tests/ui/macros/restricted-shadowing-legacy.rs
@@ -0,0 +1,289 @@
+// Legend:
+// `N` - number of combination, from 0 to 4*4*4=64
+// `Outer < Invoc` means that expansion that produced macro definition `Outer`
+// is a strict ancestor of expansion that produced macro definition `Inner`.
+// `>`, `=` and `Unordered` mean "strict descendant", "same" and
+// "not in ordering relation" for parent expansions.
+// `+` - possible configuration
+// `-` - configuration impossible due to properties of partial ordering
+// `-?` - configuration impossible due to block/scope syntax
+// `+?` - configuration possible only with legacy scoping
+
+//  N | Outer ~ Invoc | Invoc ~ Inner | Outer ~ Inner | Possible |
+//  1 |       <       |       <       |       <       |    +     |
+//  2 |       <       |       <       |       =       |    -     |
+//  3 |       <       |       <       |       >       |    -     |
+//  4 |       <       |       <       |   Unordered   |    -     |
+//  5 |       <       |       =       |       <       |    +     |
+//  6 |       <       |       =       |       =       |    -     |
+//  7 |       <       |       =       |       >       |    -     |
+//  8 |       <       |       =       |   Unordered   |    -     |
+//  9 |       <       |       >       |       <       |    +     |
+// 10 |       <       |       >       |       =       |    +     |
+// 11 |       <       |       >       |       >       |    -?    |
+// 12 |       <       |       >       |   Unordered   |    -?    |
+// 13 |       <       |   Unordered   |       <       |    +     |
+// 14 |       <       |   Unordered   |       =       |    -     |
+// 15 |       <       |   Unordered   |       >       |    -     |
+// 16 |       <       |   Unordered   |   Unordered   |    -?    |
+// 17 |       =       |       <       |       <       |    +     |
+// 18 |       =       |       <       |       =       |    -     |
+// 19 |       =       |       <       |       >       |    -     |
+// 20 |       =       |       <       |   Unordered   |    -     |
+// 21 |       =       |       =       |       <       |    -     |
+// 22 |       =       |       =       |       =       |    +     |
+// 23 |       =       |       =       |       >       |    -     |
+// 24 |       =       |       =       |   Unordered   |    -     |
+// 25 |       =       |       >       |       <       |    -     |
+// 26 |       =       |       >       |       =       |    -     |
+// 27 |       =       |       >       |       >       |    -?    |
+// 28 |       =       |       >       |   Unordered   |    -     |
+// 29 |       =       |   Unordered   |       <       |    -     |
+// 30 |       =       |   Unordered   |       =       |    -     |
+// 31 |       =       |   Unordered   |       >       |    -     |
+// 32 |       =       |   Unordered   |   Unordered   |    -?    |
+// 33 |       >       |       <       |       <       |    +?    |
+// 34 |       >       |       <       |       =       |    +?    |
+// 35 |       >       |       <       |       >       |    +?    |
+// 36 |       >       |       <       |   Unordered   |    +     |
+// 37 |       >       |       =       |       <       |    -     |
+// 38 |       >       |       =       |       =       |    -     |
+// 39 |       >       |       =       |       >       |    +     |
+// 40 |       >       |       =       |   Unordered   |    -     |
+// 41 |       >       |       >       |       <       |    -     |
+// 42 |       >       |       >       |       =       |    -     |
+// 43 |       >       |       >       |       >       |    -?    |
+// 44 |       >       |       >       |   Unordered   |    -     |
+// 45 |       >       |   Unordered   |       <       |    -     |
+// 46 |       >       |   Unordered   |       =       |    -     |
+// 47 |       >       |   Unordered   |       >       |    -?    |
+// 48 |       >       |   Unordered   |   Unordered   |    -?    |
+// 49 |   Unordered   |       <       |       <       |    -?    |
+// 50 |   Unordered   |       <       |       =       |    -     |
+// 51 |   Unordered   |       <       |       >       |    -     |
+// 52 |   Unordered   |       <       |   Unordered   |    +     |
+// 53 |   Unordered   |       =       |       <       |    -     |
+// 54 |   Unordered   |       =       |       =       |    -     |
+// 55 |   Unordered   |       =       |       >       |    -     |
+// 56 |   Unordered   |       =       |   Unordered   |    +     |
+// 57 |   Unordered   |       >       |       <       |    -     |
+// 58 |   Unordered   |       >       |       =       |    -     |
+// 59 |   Unordered   |       >       |       >       |    +     |
+// 60 |   Unordered   |       >       |   Unordered   |    +     |
+// 61 |   Unordered   |   Unordered   |       <       |    +?    |
+// 62 |   Unordered   |   Unordered   |       =       |    +?    |
+// 63 |   Unordered   |   Unordered   |       >       |    +?    |
+// 64 |   Unordered   |   Unordered   |   Unordered   |    +     |
+
+#![feature(decl_macro, rustc_attrs)]
+
+struct Right;
+// struct Wrong; // not defined
+
+macro_rules! include { () => {
+    macro_rules! gen_outer { () => {
+        macro_rules! m { () => { Wrong } }
+    }}
+    macro_rules! gen_inner { () => {
+        macro_rules! m { () => { Right } }
+    }}
+    macro_rules! gen_invoc { () => {
+        m!()
+    }}
+
+    // -----------------------------------------------------------
+
+    fn check1() {
+        macro_rules! m { () => {} }
+
+        macro_rules! gen_gen_inner_invoc { () => {
+            gen_inner!();
+            m!(); //~ ERROR `m` is ambiguous
+        }}
+        gen_gen_inner_invoc!();
+    }
+
+    fn check5() {
+        macro_rules! m { () => { Wrong } }
+
+        macro_rules! gen_inner_invoc { () => {
+            macro_rules! m { () => { Right } }
+            m!(); // OK
+        }}
+        gen_inner_invoc!();
+    }
+
+    fn check9() {
+        macro_rules! m { () => { Wrong } }
+
+        macro_rules! gen_inner_gen_invoc { () => {
+            macro_rules! m { () => { Right } }
+            gen_invoc!(); // OK
+        }}
+        gen_inner_gen_invoc!();
+    }
+
+    fn check10() {
+        macro_rules! m { () => { Wrong } }
+
+        macro_rules! m { () => { Right } }
+
+        gen_invoc!(); // OK
+    }
+
+    fn check13() {
+        macro_rules! m { () => {} }
+
+        gen_inner!();
+
+        macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous
+        gen_invoc!();
+    }
+
+    fn check17() {
+        macro_rules! m { () => {} }
+
+        gen_inner!();
+
+        m!(); //~ ERROR `m` is ambiguous
+    }
+
+    fn check22() {
+        macro_rules! m { () => { Wrong } }
+
+        macro_rules! m { () => { Right } }
+
+        m!(); // OK
+    }
+
+    fn check36() {
+        gen_outer!();
+
+        gen_inner!();
+
+        m!(); //~ ERROR `m` is ambiguous
+    }
+
+    fn check39() {
+        gen_outer!();
+
+        macro_rules! m { () => { Right } }
+
+        m!(); // OK
+    }
+
+    fn check52() {
+        gen_outer!();
+
+        macro_rules! gen_gen_inner_invoc { () => {
+            gen_inner!();
+            m!(); //~ ERROR `m` is ambiguous
+        }}
+        gen_gen_inner_invoc!();
+    }
+
+    fn check56() {
+        gen_outer!();
+
+        macro_rules! gen_inner_invoc { () => {
+            macro_rules! m { () => { Right } }
+            m!(); // OK
+        }}
+        gen_inner_invoc!();
+    }
+
+    fn check59() {
+        gen_outer!();
+
+        macro_rules! m { () => { Right } }
+
+        gen_invoc!(); // OK
+    }
+
+    fn check60() {
+        gen_outer!();
+
+        macro_rules! gen_inner_gen_invoc { () => {
+            macro_rules! m { () => { Right } }
+            gen_invoc!(); // OK
+        }}
+        gen_inner_gen_invoc!();
+    }
+
+    fn check64() {
+        gen_outer!();
+
+        gen_inner!();
+
+        macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous
+        gen_invoc!();
+    }
+
+    // -----------------------------------------------------------
+    // These configurations are only possible with legacy macro scoping
+
+    fn check33() {
+        macro_rules! gen_outer_gen_inner { () => {
+            macro_rules! m { () => {} }
+            gen_inner!();
+        }}
+        gen_outer_gen_inner!();
+
+        m!(); //~ ERROR `m` is ambiguous
+    }
+
+    fn check34() {
+        macro_rules! gen_outer_inner { () => {
+            macro_rules! m { () => { Wrong } }
+            macro_rules! m { () => { Right } }
+        }}
+        gen_outer_inner!();
+
+        m!(); // OK
+    }
+
+    fn check35() {
+        macro_rules! gen_gen_outer_inner { () => {
+            gen_outer!();
+            macro_rules! m { () => { Right } }
+        }}
+        gen_gen_outer_inner!();
+
+        m!(); // OK
+    }
+
+    fn check61() {
+        macro_rules! gen_outer_gen_inner { () => {
+            macro_rules! m { () => {} }
+            gen_inner!();
+        }}
+        gen_outer_gen_inner!();
+
+        macro_rules! gen_invoc { () => { m!() } } //~ ERROR `m` is ambiguous
+        gen_invoc!();
+    }
+
+    fn check62() {
+        macro_rules! gen_outer_inner { () => {
+            macro_rules! m { () => { Wrong } }
+            macro_rules! m { () => { Right } }
+        }}
+        gen_outer_inner!();
+
+        gen_invoc!(); // OK
+    }
+
+    fn check63() {
+        macro_rules! gen_gen_outer_inner { () => {
+            gen_outer!();
+            macro_rules! m { () => { Right } }
+        }}
+        gen_gen_outer_inner!();
+
+        gen_invoc!(); // OK
+    }
+}}
+
+include!();
+
+fn main() {}
diff --git a/tests/ui/macros/restricted-shadowing-legacy.stderr b/tests/ui/macros/restricted-shadowing-legacy.stderr
new file mode 100644
index 00000000000..b8865112ed5
--- /dev/null
+++ b/tests/ui/macros/restricted-shadowing-legacy.stderr
@@ -0,0 +1,227 @@
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:101:13
+   |
+LL |             m!();
+   |             ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:97:9
+   |
+LL |         macro_rules! m { () => {} }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:139:42
+   |
+LL |         macro_rules! gen_invoc { () => { m!() } }
+   |                                          ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:135:9
+   |
+LL |         macro_rules! m { () => {} }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:148:9
+   |
+LL |         m!();
+   |         ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:144:9
+   |
+LL |         macro_rules! m { () => {} }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:164:9
+   |
+LL |         m!();
+   |         ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:85:9
+   |
+LL |         macro_rules! m { () => { Wrong } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:180:13
+   |
+LL |             m!();
+   |             ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:85:9
+   |
+LL |         macro_rules! m { () => { Wrong } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:218:42
+   |
+LL |         macro_rules! gen_invoc { () => { m!() } }
+   |                                          ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:85:9
+   |
+LL |         macro_rules! m { () => { Wrong } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:232:9
+   |
+LL |         m!();
+   |         ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:227:13
+   |
+LL |             macro_rules! m { () => {} }
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-legacy.rs:262:42
+   |
+LL |         macro_rules! gen_invoc { () => { m!() } }
+   |                                          ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:88:9
+   |
+LL |         macro_rules! m { () => { Right } }
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-legacy.rs:257:13
+   |
+LL |             macro_rules! m { () => {} }
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/restricted-shadowing-modern.rs b/tests/ui/macros/restricted-shadowing-modern.rs
new file mode 100644
index 00000000000..1151a829eba
--- /dev/null
+++ b/tests/ui/macros/restricted-shadowing-modern.rs
@@ -0,0 +1,241 @@
+// Legend:
+// `N` - number of combination, from 0 to 4*4*4=64
+// `Outer < Invoc` means that expansion that produced macro definition `Outer`
+// is a strict ancestor of expansion that produced macro definition `Inner`.
+// `>`, `=` and `Unordered` mean "strict descendant", "same" and
+// "not in ordering relation" for parent expansions.
+// `+` - possible configuration
+// `-` - configuration impossible due to properties of partial ordering
+// `-?` - configuration impossible due to block/scope syntax
+// `+?` - configuration possible only with legacy scoping
+
+//  N | Outer ~ Invoc | Invoc ~ Inner | Outer ~ Inner | Possible |
+//  1 |       <       |       <       |       <       |    +     |
+//  2 |       <       |       <       |       =       |    -     |
+//  3 |       <       |       <       |       >       |    -     |
+//  4 |       <       |       <       |   Unordered   |    -     |
+//  5 |       <       |       =       |       <       |    +     |
+//  6 |       <       |       =       |       =       |    -     |
+//  7 |       <       |       =       |       >       |    -     |
+//  8 |       <       |       =       |   Unordered   |    -     |
+//  9 |       <       |       >       |       <       |    +     |
+// 10 |       <       |       >       |       =       |    +     |
+// 11 |       <       |       >       |       >       |    -?    |
+// 12 |       <       |       >       |   Unordered   |    -?    |
+// 13 |       <       |   Unordered   |       <       |    +     |
+// 14 |       <       |   Unordered   |       =       |    -     |
+// 15 |       <       |   Unordered   |       >       |    -     |
+// 16 |       <       |   Unordered   |   Unordered   |    -?    |
+// 17 |       =       |       <       |       <       |    +     |
+// 18 |       =       |       <       |       =       |    -     |
+// 19 |       =       |       <       |       >       |    -     |
+// 20 |       =       |       <       |   Unordered   |    -     |
+// 21 |       =       |       =       |       <       |    -     |
+// 22 |       =       |       =       |       =       |    +     |
+// 23 |       =       |       =       |       >       |    -     |
+// 24 |       =       |       =       |   Unordered   |    -     |
+// 25 |       =       |       >       |       <       |    -     |
+// 26 |       =       |       >       |       =       |    -     |
+// 27 |       =       |       >       |       >       |    -?    |
+// 28 |       =       |       >       |   Unordered   |    -     |
+// 29 |       =       |   Unordered   |       <       |    -     |
+// 30 |       =       |   Unordered   |       =       |    -     |
+// 31 |       =       |   Unordered   |       >       |    -     |
+// 32 |       =       |   Unordered   |   Unordered   |    -?    |
+// 33 |       >       |       <       |       <       |    -?    |
+// 34 |       >       |       <       |       =       |    -?    |
+// 35 |       >       |       <       |       >       |    -?    |
+// 36 |       >       |       <       |   Unordered   |    +     |
+// 37 |       >       |       =       |       <       |    -     |
+// 38 |       >       |       =       |       =       |    -     |
+// 39 |       >       |       =       |       >       |    +     |
+// 40 |       >       |       =       |   Unordered   |    -     |
+// 41 |       >       |       >       |       <       |    -     |
+// 42 |       >       |       >       |       =       |    -     |
+// 43 |       >       |       >       |       >       |    -?    |
+// 44 |       >       |       >       |   Unordered   |    -     |
+// 45 |       >       |   Unordered   |       <       |    -     |
+// 46 |       >       |   Unordered   |       =       |    -     |
+// 47 |       >       |   Unordered   |       >       |    -?    |
+// 48 |       >       |   Unordered   |   Unordered   |    -?    |
+// 49 |   Unordered   |       <       |       <       |    -?    |
+// 50 |   Unordered   |       <       |       =       |    -     |
+// 51 |   Unordered   |       <       |       >       |    -     |
+// 52 |   Unordered   |       <       |   Unordered   |    +     |
+// 53 |   Unordered   |       =       |       <       |    -     |
+// 54 |   Unordered   |       =       |       =       |    -     |
+// 55 |   Unordered   |       =       |       >       |    -     |
+// 56 |   Unordered   |       =       |   Unordered   |    +     |
+// 57 |   Unordered   |       >       |       <       |    -     |
+// 58 |   Unordered   |       >       |       =       |    -     |
+// 59 |   Unordered   |       >       |       >       |    +     |
+// 60 |   Unordered   |       >       |   Unordered   |    +     |
+// 61 |   Unordered   |   Unordered   |       <       |    -?    |
+// 62 |   Unordered   |   Unordered   |       =       |    -?    |
+// 63 |   Unordered   |   Unordered   |       >       |    -?    |
+// 64 |   Unordered   |   Unordered   |   Unordered   |    +     |
+
+#![feature(decl_macro, rustc_attrs)]
+
+struct Right;
+// struct Wrong; // not defined
+
+#[rustc_macro_transparency = "transparent"]
+macro include() {
+    #[rustc_macro_transparency = "transparent"]
+    macro gen_outer() {
+        macro m() { Wrong }
+    }
+    #[rustc_macro_transparency = "transparent"]
+    macro gen_inner() {
+        macro m() { Right }
+    }
+    #[rustc_macro_transparency = "transparent"]
+    macro gen_invoc() {
+        m!()
+    }
+
+    fn check1() {
+        macro m() {}
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_gen_inner_invoc() {
+                gen_inner!();
+                m!(); //~ ERROR `m` is ambiguous
+            }
+            gen_gen_inner_invoc!();
+        }
+    }
+
+    fn check5() {
+        macro m() { Wrong }
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_inner_invoc() {
+                macro m() { Right }
+                m!(); // OK
+            }
+            gen_inner_invoc!();
+        }
+    }
+
+    fn check9() {
+        macro m() { Wrong }
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_inner_gen_invoc() {
+                macro m() { Right }
+                gen_invoc!(); // OK
+            }
+            gen_inner_gen_invoc!();
+        }
+    }
+
+    fn check10() {
+        macro m() { Wrong }
+        {
+            macro m() { Right }
+            gen_invoc!(); // OK
+        }
+    }
+
+    fn check13() {
+        macro m() {}
+        {
+            gen_inner!();
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous
+            gen_invoc!();
+        }
+    }
+
+    fn check17() {
+        macro m() {}
+        {
+            gen_inner!();
+            m!(); //~ ERROR `m` is ambiguous
+        }
+    }
+
+    fn check22() {
+        macro m() { Wrong }
+        {
+            macro m() { Right }
+            m!(); // OK
+        }
+    }
+
+    fn check36() {
+        gen_outer!();
+        {
+            gen_inner!();
+            m!(); //~ ERROR `m` is ambiguous
+        }
+    }
+
+    fn check39() {
+        gen_outer!();
+        {
+            macro m() { Right }
+            m!(); // OK
+        }
+    }
+
+    fn check52() {
+        gen_outer!();
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_gen_inner_invoc() {
+                gen_inner!();
+                m!(); //~ ERROR `m` is ambiguous
+            }
+            gen_gen_inner_invoc!();
+        }
+    }
+
+    fn check56() {
+        gen_outer!();
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_inner_invoc() {
+                macro m() { Right }
+                m!(); // OK
+            }
+            gen_inner_invoc!();
+        }
+    }
+
+    fn check59() {
+        gen_outer!();
+        {
+            macro m() { Right }
+            gen_invoc!(); // OK
+        }
+    }
+
+    fn check60() {
+        gen_outer!();
+        {
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_inner_gen_invoc() {
+                macro m() { Right }
+                gen_invoc!(); // OK
+            }
+            gen_inner_gen_invoc!();
+        }
+    }
+
+    fn check64() {
+        gen_outer!();
+        {
+            gen_inner!();
+            #[rustc_macro_transparency = "transparent"]
+            macro gen_invoc() { m!() } //~ ERROR `m` is ambiguous
+            gen_invoc!();
+        }
+    }
+}
+
+include!();
+
+fn main() {}
diff --git a/tests/ui/macros/restricted-shadowing-modern.stderr b/tests/ui/macros/restricted-shadowing-modern.stderr
new file mode 100644
index 00000000000..27665bfc310
--- /dev/null
+++ b/tests/ui/macros/restricted-shadowing-modern.stderr
@@ -0,0 +1,171 @@
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:104:17
+   |
+LL |                 m!();
+   |                 ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:99:9
+   |
+LL |         macro m() {}
+   |         ^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:147:33
+   |
+LL |             macro gen_invoc() { m!() }
+   |                                 ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:143:9
+   |
+LL |         macro m() {}
+   |         ^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:156:13
+   |
+LL |             m!();
+   |             ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:153:9
+   |
+LL |         macro m() {}
+   |         ^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:172:13
+   |
+LL |             m!();
+   |             ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:87:9
+   |
+LL |         macro m() { Wrong }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:190:17
+   |
+LL |                 m!();
+   |                 ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:87:9
+   |
+LL |         macro m() { Wrong }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_gen_inner_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0659]: `m` is ambiguous
+  --> $DIR/restricted-shadowing-modern.rs:233:33
+   |
+LL |             macro gen_invoc() { m!() }
+   |                                 ^ ambiguous name
+...
+LL | include!();
+   | ---------- in this macro invocation
+   |
+   = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
+note: `m` could refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:91:9
+   |
+LL |         macro m() { Right }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+note: `m` could also refer to the macro defined here
+  --> $DIR/restricted-shadowing-modern.rs:87:9
+   |
+LL |         macro m() { Wrong }
+   |         ^^^^^^^^^^^^^^^^^^^
+...
+LL | include!();
+   | ---------- in this macro invocation
+   = note: this error originates in the macro `gen_invoc` which comes from the expansion of the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
new file mode 100644
index 00000000000..b8b6f0846bb
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs
@@ -0,0 +1,186 @@
+// edition:2021
+// ignore-tidy-linelength
+// only-x86_64
+// run-pass
+// needs-unwind Asserting on contents of error message
+
+#![allow(path_statements, unused_allocation)]
+#![feature(box_syntax, core_intrinsics, generic_assert, generic_assert_internals)]
+
+macro_rules! test {
+  (
+    let mut $elem_ident:ident = $elem_expr:expr;
+    [ $($assert:tt)* ] => $msg:literal
+  ) => {
+    {
+      #[allow(unused_assignments, unused_mut, unused_variables)]
+      let rslt = std::panic::catch_unwind(|| {
+        let mut $elem_ident = $elem_expr;
+        assert!($($assert)*);
+      });
+      let err = rslt.unwrap_err();
+      if let Some(elem) = err.downcast_ref::<String>() {
+        assert_eq!(elem, &$msg);
+      }
+      else if let Some(elem) = err.downcast_ref::<&str>() {
+        assert_eq!(elem, &$msg);
+      }
+      else {
+        panic!("assert!( ... ) should return a string");
+      }
+    }
+  }
+}
+
+macro_rules! tests {
+  (
+    let mut $elem_ident:ident = $elem_expr:expr;
+
+    $(
+      [ $($elem_assert:tt)* ] => $elem_msg:literal
+    )+
+  ) => {
+    $(
+      test!(
+        let mut $elem_ident = $elem_expr;
+        [ $($elem_assert)* ] => $elem_msg
+      );
+    )+
+  }
+}
+
+const FOO: Foo = Foo { bar: 1 };
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+struct Foo {
+  bar: i32
+}
+
+impl Foo {
+  fn add(&self, a: i32, b: i32) -> i32 { a + b }
+}
+
+fn add(a: i32, b: i32) -> i32 { a + b }
+
+fn main() {
+  // ***** Allowed *****
+
+  tests!(
+    let mut elem = 1i32;
+
+    // addr of
+    [ &elem == &3 ] => "Assertion failed: &elem == &3\nWith captures:\n  elem = 1\n"
+
+    // array
+    [ [elem][0] == 3 ] => "Assertion failed: [elem][0] == 3\nWith captures:\n  elem = 1\n"
+
+    // binary
+    [ elem + 1 == 3 ] => "Assertion failed: elem + 1 == 3\nWith captures:\n  elem = 1\n"
+
+    // call
+    [ add(elem, elem) == 3 ] => "Assertion failed: add(elem, elem) == 3\nWith captures:\n  elem = 1\n"
+
+    // cast
+    [ elem as i32 == 3 ] => "Assertion failed: elem as i32 == 3\nWith captures:\n  elem = 1\n"
+
+    // index
+    [ [1i32, 1][elem as usize] == 3 ] => "Assertion failed: [1i32, 1][elem as usize] == 3\nWith captures:\n  elem = 1\n"
+
+    // method call
+    [ FOO.add(elem, elem) == 3 ] => "Assertion failed: FOO.add(elem, elem) == 3\nWith captures:\n  elem = 1\n"
+
+    // paren
+    [ (elem) == 3 ] => "Assertion failed: (elem) == 3\nWith captures:\n  elem = 1\n"
+
+    // range
+    [ (0..elem) == (0..3) ] => "Assertion failed: (0..elem) == (0..3)\nWith captures:\n  elem = 1\n"
+
+    // repeat
+    [ [elem; 1] == [3; 1] ] => "Assertion failed: [elem; 1] == [3; 1]\nWith captures:\n  elem = 1\n"
+
+    // struct
+    [ Foo { bar: elem } == Foo { bar: 3 } ] => "Assertion failed: Foo { bar: elem } == Foo { bar: 3 }\nWith captures:\n  elem = 1\n"
+
+    // tuple
+    [ (elem, 1) == (3, 3) ] => "Assertion failed: (elem, 1) == (3, 3)\nWith captures:\n  elem = 1\n"
+
+    // unary
+    [ -elem == -3 ] => "Assertion failed: -elem == -3\nWith captures:\n  elem = 1\n"
+  );
+
+  // ***** Disallowed *****
+
+  tests!(
+    let mut elem = 1i32;
+
+    // assign
+    [ { let local = elem; local } == 3 ] => "Assertion failed: { let local = elem; local } == 3"
+
+    // assign op
+    [ { elem += 1; elem } == 3 ] => "Assertion failed: { elem += 1; elem } == 3"
+
+    // async
+    [ { let _ = async { elem }; elem } == 3 ] => "Assertion failed: { let _ = async { elem }; elem } == 3"
+
+    // await
+
+    // block
+    [ { elem } == 3 ] => "Assertion failed: { elem } == 3"
+
+    // box
+    [ box elem == box 3 ] => "Assertion failed: box elem == box 3"
+
+    // break
+    [ loop { break elem; } ==  3 ] => "Assertion failed: loop { break elem; } == 3"
+
+    // closure
+    [(|| elem)() ==  3 ] => "Assertion failed: (|| elem)() == 3"
+
+    // const block
+
+    // continue
+
+    // err
+
+    // field
+    [ FOO.bar ==  3 ] => "Assertion failed: FOO.bar == 3"
+
+    // for loop
+    [ { for _ in 0..elem { elem; } elem } ==  3 ] => "Assertion failed: { for _ in 0..elem { elem; } elem } == 3"
+
+    // if
+    [ if true { elem } else { elem } == 3 ] => "Assertion failed: if true { elem } else { elem } == 3"
+
+    // inline asm
+
+    // let
+    [ if let true = true { elem } else { elem } == 3 ] => "Assertion failed: if let true = true { elem } else { elem } == 3"
+
+    // lit
+
+    // loop
+    [ loop { elem; break elem; } == 3 ] => "Assertion failed: loop { elem; break elem; } == 3"
+
+    // mac call
+
+    // match
+    [ match elem { _ => elem } == 3 ] => "Assertion failed: match elem { _ => elem, } == 3"
+
+    // ret
+    [ (|| { return elem; })() == 3 ] => "Assertion failed: (|| { return elem; })() == 3"
+
+    // try
+    [ (|| { Some(Some(elem)?) })() == Some(3) ] => "Assertion failed: (|| { Some(Some(elem)?) })() == Some(3)"
+
+    // try block
+
+    // underscore
+
+    // while
+    [ { while false { elem; break; } elem } == 3 ] => "Assertion failed: { while false { elem; break; } elem } == 3"
+
+    // yeet
+
+    // yield
+  );
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
new file mode 100644
index 00000000000..d46f396ee29
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
@@ -0,0 +1,44 @@
+// aux-build:common.rs
+// ignore-tidy-linelength
+// only-x86_64
+// run-pass
+// needs-unwind Asserting on contents of error message
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+extern crate common;
+
+#[derive(Clone, Copy, PartialEq)]
+struct CopyNoDebug(i32);
+
+#[derive(Debug, PartialEq)]
+struct NoCopyDebug(i32);
+
+#[derive(PartialEq)]
+struct NoCopyNoDebug(i32);
+
+fn main() {
+  // Has Copy but does not have Debug
+  common::test!(
+    let mut copy_no_debug = CopyNoDebug(1);
+    [ copy_no_debug == CopyNoDebug(3) ] => "Assertion failed: copy_no_debug == CopyNoDebug(3)\nWith captures:\n  copy_no_debug = N/A\n"
+  );
+
+  // Does not have Copy but has Debug
+  common::test!(
+    let mut no_copy_debug = NoCopyDebug(1);
+    [ no_copy_debug == NoCopyDebug(3) ] => "Assertion failed: no_copy_debug == NoCopyDebug(3)\nWith captures:\n  no_copy_debug = N/A\n"
+  );
+
+  // Does not have Copy and does not have Debug
+  common::test!(
+    let mut no_copy_no_debug = NoCopyNoDebug(1);
+    [ no_copy_no_debug == NoCopyNoDebug(3) ] => "Assertion failed: no_copy_no_debug == NoCopyNoDebug(3)\nWith captures:\n  no_copy_no_debug = N/A\n"
+  );
+
+  // Unevaluated (Expression short-circuited)
+  common::test!(
+    let mut elem = true;
+    [ false && elem ] => "Assertion failed: false && elem\nWith captures:\n  elem = N/A\n"
+  );
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
new file mode 100644
index 00000000000..6a1435f792b
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
@@ -0,0 +1,13 @@
+// compile-flags: --test
+// run-pass
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+#[should_panic(expected = "Custom user message")]
+#[test]
+fn test() {
+  assert!(1 == 3, "Custom user message");
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
new file mode 100644
index 00000000000..1f5a29ab524
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
@@ -0,0 +1,15 @@
+// aux-build:common.rs
+// only-x86_64
+// run-pass
+// needs-unwind Asserting on contents of error message
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+extern crate common;
+
+fn main() {
+  common::test!(
+    let mut _nothing = ();
+    [ 1 == 3 ] => "Assertion failed: 1 == 3"
+  );
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs
new file mode 100644
index 00000000000..903ed507c2e
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs
@@ -0,0 +1,25 @@
+#[macro_export]
+macro_rules! test {
+  (
+    let mut $elem_ident:ident = $elem_expr:expr;
+    [ $($assert:tt)* ] => $msg:literal
+  ) => {
+    {
+      #[allow(unused_assignments, unused_mut, unused_variables)]
+      let rslt = std::panic::catch_unwind(|| {
+        let mut $elem_ident = $elem_expr;
+        assert!($($assert)*);
+      });
+      let err = rslt.unwrap_err();
+      if let Some(elem) = err.downcast_ref::<String>() {
+        assert_eq!(elem, &$msg);
+      }
+      else if let Some(elem) = err.downcast_ref::<&str>() {
+        assert_eq!(elem, &$msg);
+      }
+      else {
+        panic!("assert!( ... ) should return a string");
+      }
+    }
+  }
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
new file mode 100644
index 00000000000..01860adaac2
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
@@ -0,0 +1,26 @@
+// compile-flags: --test
+// ignore-tidy-linelength
+// run-pass
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+use std::fmt::{Debug, Formatter};
+
+#[derive(Clone, Copy, PartialEq)]
+struct CopyDebug(i32);
+
+impl Debug for CopyDebug {
+  fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+    f.write_str("With great power comes great electricity bills")
+  }
+}
+
+#[should_panic(expected = "Assertion failed: copy_debug == CopyDebug(3)\nWith captures:\n  copy_debug = With great power comes great electricity bills\n")]
+#[test]
+fn test() {
+  let copy_debug = CopyDebug(1);
+  assert!(copy_debug == CopyDebug(3));
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
new file mode 100644
index 00000000000..5ec84b08ff8
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
@@ -0,0 +1,32 @@
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    assert!(elem as usize);
+}
+
+fn addr_of() {
+    let elem = 1i32;
+    assert!(&elem);
+}
+
+fn binary() {
+    let elem = 1i32;
+    assert!(elem == 1);
+    assert!(elem >= 1);
+    assert!(elem > 0);
+    assert!(elem < 3);
+    assert!(elem <= 3);
+    assert!(elem != 3);
+}
+
+fn unary() {
+    let elem = &1i32;
+    assert!(*elem);
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
new file mode 100644
index 00000000000..90f858f80e6
--- /dev/null
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -0,0 +1,147 @@
+#![feature(prelude_import)]
+#![no_std]
+// check-pass
+// compile-flags: -Z unpretty=expanded
+
+#![feature(core_intrinsics, generic_assert, generic_assert_internals)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+fn arbitrary_consuming_method_for_demonstration_purposes() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*{
+                                    (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                                    __local_bind0
+                                } as usize)) {
+
+
+
+
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn addr_of() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!&*__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn binary() {
+    let elem = 1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn unary() {
+    let elem = &1i32;
+    {
+        #[allow(unused_imports)]
+        use ::core::asserting::{TryCaptureGeneric, TryCapturePrintable};
+        let mut __capture0 = ::core::asserting::Capture::new();
+        let __local_bind0 = &elem;
+        if ::core::intrinsics::unlikely(!**__local_bind0) {
+                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                {
+                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n  elem = ",
+                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                }
+            }
+    };
+}
+fn main() {}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
new file mode 100644
index 00000000000..ab8d95a41d0
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -0,0 +1,271 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+fn main() {
+    macro_rules! one_nested_count_and_length {
+        ( $( [ $( $l:literal ),* ] ),* ) => {
+            [
+                // outer-most repetition
+                $(
+                    // inner-most repetition
+                    $(
+                        ${ignore(l)} ${index()}, ${length()},
+                    )*
+                    ${count(l)}, ${index()}, ${length()},
+                )*
+                ${count(l)},
+            ]
+        };
+    }
+    assert_eq!(
+        one_nested_count_and_length!(["foo"], ["bar", "baz"]),
+        [
+            // # ["foo"]
+
+            // ## inner-most repetition (first iteration)
+            //
+            // `index` is 0 because this is the first inner-most iteration.
+            // `length` is 1 because there is only one inner-most repetition, "foo".
+            0, 1,
+
+            // ## outer-most repetition (first iteration)
+            //
+            // `count` is 1 because of "foo", i,e, `$l` has only one repetition,
+            // `index` is 0 because this is the first outer-most iteration.
+            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            1, 0, 2,
+
+            // # ["bar", "baz"]
+
+            // ## inner-most repetition (first iteration)
+            //
+            // `index` is 0 because this is the first inner-most iteration
+            // `length` is 2 because there are repetitions, "bar" and "baz"
+            0, 2,
+
+            // ## inner-most repetition (second iteration)
+            //
+            // `index` is 1 because this is the second inner-most iteration
+            // `length` is 2 because there are repetitions, "bar" and "baz"
+            1, 2,
+
+            // ## outer-most repetition (second iteration)
+            //
+            // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
+            // `index` is 1 because this is the second outer-most iteration
+            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            2, 1, 2,
+
+            // # last count
+
+            // Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz"
+            3,
+        ]
+    );
+
+    // Based on the above explanation, the following macros should be straightforward
+
+    // Grouped from the outer-most to the inner-most
+    macro_rules! three_nested_count {
+        ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+            &[
+                $( $( $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                    ][..],
+                )* )* )*
+
+                $( $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                        ${ignore(i)} ${count(i, 1)},
+                    ][..],
+                )* )*
+
+                $(
+                    &[
+                        ${ignore(i)} ${count(i, 0)},
+                        ${ignore(i)} ${count(i, 1)},
+                        ${ignore(i)} ${count(i, 2)},
+                    ][..],
+                )*
+
+                &[
+                    ${count(i, 0)},
+                    ${count(i, 1)},
+                    ${count(i, 2)},
+                    ${count(i, 3)},
+                ][..]
+            ][..]
+        }
+    }
+    assert_eq!(
+        three_nested_count!(
+            {
+                [ (a b c) (d e f) ]
+                [ (g h) (i j k l m) ]
+                [ (n) ]
+            }
+            {
+                [ (o) (p q) (r s) ]
+                [ (t u v w x y z) ]
+            }
+        ),
+        &[
+            // a b c
+            &[3][..],
+            // d e f
+            &[3][..],
+            // g h
+            &[2][..],
+            // i j k l m
+            &[5][..],
+            // n
+            &[1][..],
+            // o
+            &[1][..],
+            // p q
+            &[2][..],
+            // r s
+            &[2][..],
+            // t u v w x y z
+            &[7][..],
+
+            // (a b c) (d e f)
+            &[2, 6][..],
+            // (g h) (i j k l m)
+            &[2, 7][..],
+            // (n)
+            &[1, 1][..],
+            // (o) (p q) (r s)
+            &[3, 5][..],
+            // (t u v w x y z)
+            &[1, 7][..],
+
+            // [ (a b c) (d e f) ]
+            // [ (g h) (i j k l m) ]
+            // [ (n) ]
+            &[3, 5, 14][..],
+            // [ (o) (p q) (r s) ]
+            // [ (t u v w x y z) ]
+            &[2, 4, 12][..],
+
+            // {
+            //     [ (a b c) (d e f) ]
+            //     [ (g h) (i j k l m) ]
+            //     [ (n) ]
+            // }
+            // {
+            //     [ (o) (p q) (r s) ]
+            //     [ (t u v w x y z) ]
+            // }
+            &[2, 5, 9, 26][..]
+        ][..]
+    );
+
+    // Grouped from the outer-most to the inner-most
+    macro_rules! three_nested_length {
+        ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+            &[
+                $( $( $( $(
+                    &[
+                        ${ignore(i)} ${length(3)},
+                        ${ignore(i)} ${length(2)},
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )* )* )*
+
+                $( $( $(
+                    &[
+                        ${ignore(i)} ${length(2)},
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )* )*
+
+                $( $(
+                    &[
+                        ${ignore(i)} ${length(1)},
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )* )*
+
+                $(
+                    &[
+                        ${ignore(i)} ${length(0)},
+                    ][..],
+                )*
+            ][..]
+        }
+    }
+    assert_eq!(
+        three_nested_length!(
+            {
+                [ (a b c) (d e f) ]
+                [ (g h) (i j k l m) ]
+                [ (n) ]
+            }
+            {
+                [ (o) (p q) (r s) ]
+                [ (t u v w x y z) ]
+            }
+        ),
+        &[
+            // a b c
+            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            // d e f
+            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            // g h
+            &[2, 3, 2, 2][..], &[2, 3, 2, 2][..],
+            // i j k l m
+            &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
+            // n
+            &[2, 3, 1, 1][..],
+            // o
+            &[2, 2, 3, 1][..],
+            // p q
+            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            // r s
+            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            // t u v w x y z
+            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+
+            // (a b c) (d e f)
+            &[2, 3, 2][..], &[2, 3, 2][..],
+            // (g h) (i j k l m)
+            &[2, 3, 2][..], &[2, 3, 2][..],
+            // (n)
+            &[2, 3, 1][..],
+            // (o) (p q) (r s)
+            &[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..],
+            // (t u v w x y z)
+            &[2, 2, 1][..],
+
+            // [ (a b c) (d e f) ]
+            // [ (g h) (i j k l m) ]
+            // [ (n) ]
+            &[2, 3][..], &[2, 3][..],  &[2, 3,][..],
+            // [ (o) (p q) (r s) ]
+            // [ (t u v w x y z) ]
+            &[2, 2][..], &[2, 2][..],
+
+            // {
+            //     [ (a b c) (d e f) ]
+            //     [ (g h) (i j k l m) ]
+            //     [ (n) ]
+            // }
+            // {
+            //     [ (o) (p q) (r s) ]
+            //     [ (t u v w x y z) ]
+            // }
+            &[2][..], &[2][..]
+        ][..]
+    );
+
+    // It is possible to say, to some degree, that count is an "amalgamation" of length (see
+    // each length line result and compare them with the count results)
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
new file mode 100644
index 00000000000..ed94c27cf05
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! nested {
+    ( $a:ident ) => {
+        macro_rules! $a {
+            ( $$( $b:ident ),* ) => {
+                $$(
+                    macro_rules! $b {
+                        ( $$$$( $c:ident ),* ) => {
+                            $$$$(
+                                fn $c() -> &'static str { stringify!($c) }
+                            ),*
+                        };
+                    }
+                )*
+            };
+        }
+    };
+}
+
+fn main() {
+    nested!(a);
+    a!(b);
+    b!(c);
+    assert_eq!(c(), "c");
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
new file mode 100644
index 00000000000..d05cd1b31bc
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
@@ -0,0 +1,148 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+/// Count the number of idents in a macro repetition.
+macro_rules! count_idents {
+    ( $( $i:ident ),* ) => {
+        ${count(i)}
+    };
+}
+
+/// Count the number of idents in a 2-dimensional macro repetition.
+macro_rules! count_idents_2 {
+    ( $( [ $( $i:ident ),* ] ),* ) => {
+        ${count(i)}
+    };
+}
+
+/// Mostly counts the number of OUTER-MOST repetitions
+macro_rules! count_depth_limits {
+    ( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
+        (
+            (
+                ${count(inner)},
+                ${count(inner, 0)},
+                ${count(inner, 1)},
+                ${count(inner, 2)},
+                ${count(inner, 3)},
+            ),
+            (
+                ${count(outer)},
+                ${count(outer, 0)},
+                ${count(outer, 1)},
+                ${count(outer, 2)},
+            ),
+        )
+    };
+}
+
+/// Produce (index, length) pairs for literals in a macro repetition.
+/// The literal is not included in the output, so this macro uses the
+/// `ignore` meta-variable expression to create a non-expanding
+/// repetition binding.
+macro_rules! enumerate_literals {
+    ( $( ($l:stmt) ),* ) => {
+        [$( ${ignore(l)} (${index()}, ${length()}) ),*]
+    };
+}
+
+/// Produce index and length tuples for literals in a 2-dimensional
+/// macro repetition.
+macro_rules! enumerate_literals_2 {
+    ( $( [ $( ($l:literal) ),* ] ),* ) => {
+        [
+            $(
+                $(
+                    (
+                        ${index(1)},
+                        ${length(1)},
+                        ${index(0)},
+                        ${length(0)},
+                        $l
+                    ),
+                )*
+            )*
+        ]
+    };
+}
+
+/// Generate macros that count idents and then add a constant number
+/// to the count.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to.
+macro_rules! make_count_adders {
+    ( $( $i:ident, $b:literal );* ) => {
+        $(
+            macro_rules! $i {
+                ( $$( $$j:ident ),* ) => {
+                    $b + $${count(j)}
+                };
+            }
+        )*
+    };
+}
+
+make_count_adders! { plus_one, 1; plus_five, 5 }
+
+/// Generate a macro that allows selection of a particular literal
+/// from a sequence of inputs by their identifier.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to, and to allow expansion of an
+/// identifier the name of which is not known in the definition
+/// of `make_picker`.
+macro_rules! make_picker {
+    ( $m:ident => $( $i:ident ),* ; $p:ident ) => {
+        macro_rules! $m {
+            ( $( $$ $i:literal ),* ) => {
+                $$ $p
+            };
+        }
+    };
+}
+
+make_picker!(first => a, b; a);
+
+make_picker!(second => a, b; b);
+
+fn main() {
+    assert_eq!(count_idents!(a, b, c), 3);
+    assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6);
+    assert_eq!(
+        count_depth_limits! {
+            {
+                [ A: (a b c) D: (d e f) ]
+                [ G: (g h) I: (i j k l m) ]
+                [ N: (n) ]
+            }
+            {
+                [ O: (o) P: (p q) R: (r s) ]
+                [ T: (t u v w x y z) ]
+            }
+        },
+        ((26, 2, 5, 9, 26), (9, 2, 5, 9))
+    );
+    assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
+    assert_eq!(
+        enumerate_literals_2![
+            [("foo"), ("bar"), ("baz")],
+            [("qux"), ("quux"), ("quuz"), ("xyzzy")]
+        ],
+        [
+            (0, 2, 0, 3, "foo"),
+            (0, 2, 1, 3, "bar"),
+            (0, 2, 2, 3, "baz"),
+
+            (1, 2, 0, 4, "qux"),
+            (1, 2, 1, 4, "quux"),
+            (1, 2, 2, 4, "quuz"),
+            (1, 2, 3, 4, "xyzzy"),
+        ]
+    );
+    assert_eq!(plus_one!(a, b, c), 4);
+    assert_eq!(plus_five!(a, b), 7);
+    assert_eq!(first!(1, 2), 1);
+    assert_eq!(second!(1, 2), 2);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
new file mode 100644
index 00000000000..b954967c4fe
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
@@ -0,0 +1,102 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+#[derive(Debug)]
+struct Example<'a> {
+    _indexes: &'a [(u32, u32)],
+    _counts: &'a [u32],
+    _nested: Vec<Example<'a>>,
+}
+
+macro_rules! example {
+    ( $( [ $( ( $( $x:ident )* ) )* ] )* ) => {
+        Example {
+            _indexes: &[],
+            _counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}],
+            _nested: vec![
+            $(
+                Example {
+                    _indexes: &[(${index()}, ${length()})],
+                    _counts: &[${count(x, 0)}, ${count(x, 1)}],
+                    _nested: vec![
+                    $(
+                        Example {
+                            _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
+                            _counts: &[${count(x)}],
+                            _nested: vec![
+                            $(
+                                Example {
+                                    _indexes: &[
+                                        (${index(2)}, ${length(2)}),
+                                        (${index(1)}, ${length(1)}),
+                                        (${index()}, ${length()})
+                                    ],
+                                    _counts: &[],
+                                    _nested: vec![],
+                                    ${ignore(x)}
+                                }
+                            ),*
+                            ]
+                        }
+                    ),*
+                    ]
+                }
+            ),*
+            ]
+        }
+    };
+}
+
+static EXPECTED: &str = concat!(
+    "Example { _indexes: [], _counts: [2, 4, 13], _nested: [",
+    concat!(
+        "Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [",
+        concat!(
+            "Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (0, 3), (0, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (1, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (2, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (0, 3), (3, 4)], _counts: [], _nested: [] }",
+            ),
+            "] }, ",
+            "Example { _indexes: [(0, 2), (1, 3)], _counts: [4], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (1, 3), (0, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (1, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (2, 4)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (1, 3), (3, 4)], _counts: [], _nested: [] }",
+            ),
+            "] }, ",
+            "Example { _indexes: [(0, 2), (2, 3)], _counts: [2], _nested: [",
+            concat!(
+                "Example { _indexes: [(0, 2), (2, 3), (0, 2)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(0, 2), (2, 3), (1, 2)], _counts: [], _nested: [] }",
+            ),
+            "] }",
+        ),
+        "] }, ",
+        "Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [",
+        concat!(
+            "Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [",
+            concat!(
+                "Example { _indexes: [(1, 2), (0, 1), (0, 3)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(1, 2), (0, 1), (1, 3)], _counts: [], _nested: [] }, ",
+                "Example { _indexes: [(1, 2), (0, 1), (2, 3)], _counts: [], _nested: [] }",
+            ),
+            "] }",
+        ),
+        "] }",
+    ),
+    "] }",
+);
+
+fn main() {
+    let e = example! {
+        [ ( A B C D ) ( E F G H ) ( I J ) ]
+        [ ( K L M ) ]
+    };
+    let debug = format!("{:?}", e);
+    assert_eq!(debug, EXPECTED);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
new file mode 100644
index 00000000000..6a0d68bd6b1
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -0,0 +1,43 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! a {
+    ( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => {
+        (
+            ${count(foo, 0)},
+            ${count(foo, 10)},
+            //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
+        )
+    };
+}
+
+macro_rules! b {
+    ( $( { $( [ $( $foo:ident )* ] )* } )* ) => {
+        (
+            $( $( $(
+                ${ignore(foo)}
+                ${index(0)},
+                ${index(10)},
+                //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
+            )* )* )*
+        )
+    };
+}
+
+macro_rules! c {
+    ( $( { $( $foo:ident )* } )* ) => {
+        (
+            $( $(
+                ${ignore(foo)}
+                ${length(0)}
+                ${length(10)}
+                //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
+            )* )*
+        )
+    };
+}
+
+fn main() {
+    a!( { [ (a) ] [ (b c) ] } );
+    b!( { [ a b ] } );
+    c!({ a });
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
new file mode 100644
index 00000000000..236122b6465
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -0,0 +1,20 @@
+error: depth parameter on meta-variable expression `count` must be less than 4
+  --> $DIR/out-of-bounds-arguments.rs:7:14
+   |
+LL |             ${count(foo, 10)},
+   |              ^^^^^^^^^^^^^^^^
+
+error: depth parameter on meta-variable expression `index` must be less than 3
+  --> $DIR/out-of-bounds-arguments.rs:19:18
+   |
+LL |                 ${index(10)},
+   |                  ^^^^^^^^^^^
+
+error: depth parameter on meta-variable expression `length` must be less than 2
+  --> $DIR/out-of-bounds-arguments.rs:32:18
+   |
+LL |                 ${length(10)}
+   |                  ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
new file mode 100644
index 00000000000..b4fef11f1e2
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
@@ -0,0 +1,44 @@
+macro_rules! count {
+    ( $( $e:stmt ),* ) => {
+        ${ count(e) }
+        //~^ ERROR meta-variable expressions are unstable
+    };
+}
+
+macro_rules! dollar_dollar {
+    () => {
+        macro_rules! bar {
+            ( $$( $$any:tt )* ) => { $$( $$any )* };
+            //~^ ERROR meta-variable expressions are unstable
+            //~| ERROR meta-variable expressions are unstable
+            //~| ERROR meta-variable expressions are unstable
+            //~| ERROR meta-variable expressions are unstable
+        }
+    };
+}
+
+macro_rules! index {
+    ( $( $e:stmt ),* ) => {
+        $( ${ignore(e)} ${index()} )*
+        //~^ ERROR meta-variable expressions are unstable
+        //~| ERROR meta-variable expressions are unstable
+    };
+}
+
+macro_rules! ignore {
+    ( $( $i:stmt ),* ) => {{
+        0 $( + 1 ${ignore(i)} )*
+        //~^ ERROR meta-variable expressions are unstable
+    }};
+}
+
+macro_rules! length {
+    ( $( $e:stmt ),* ) => {
+        $( ${ignore(e)} ${length()} )*
+        //~^ ERROR meta-variable expressions are unstable
+        //~| ERROR meta-variable expressions are unstable
+    };
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
new file mode 100644
index 00000000000..ecf598b104d
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
@@ -0,0 +1,93 @@
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:3:10
+   |
+LL |         ${ count(e) }
+   |          ^^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:11:16
+   |
+LL |             ( $$( $$any:tt )* ) => { $$( $$any )* };
+   |                ^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:11:20
+   |
+LL |             ( $$( $$any:tt )* ) => { $$( $$any )* };
+   |                    ^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:11:39
+   |
+LL |             ( $$( $$any:tt )* ) => { $$( $$any )* };
+   |                                       ^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:11:43
+   |
+LL |             ( $$( $$any:tt )* ) => { $$( $$any )* };
+   |                                           ^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:22:13
+   |
+LL |         $( ${ignore(e)} ${index()} )*
+   |             ^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:22:26
+   |
+LL |         $( ${ignore(e)} ${index()} )*
+   |                          ^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:30:19
+   |
+LL |         0 $( + 1 ${ignore(i)} )*
+   |                   ^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:37:13
+   |
+LL |         $( ${ignore(e)} ${length()} )*
+   |             ^^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+  --> $DIR/required-feature.rs:37:26
+   |
+LL |         $( ${ignore(e)} ${length()} )*
+   |                          ^^^^^^^^^^
+   |
+   = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+   = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
new file mode 100644
index 00000000000..fdf16442d2a
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -0,0 +1,165 @@
+#![feature(macro_metavar_expr)]
+
+// `curly` = Right hand side curly brackets
+// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function"
+// `round` = Left hand side round brackets
+
+macro_rules! curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count(i) } };
+}
+
+macro_rules! curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count(i) } };
+    //~^ ERROR `count` can not be placed inside the inner-most repetition
+}
+
+macro_rules! curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! curly__rhs_dollar__no_round {
+    ( $i:ident ) => { ${ count($i) } };
+    //~^ ERROR expected identifier, found `$`
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! no_curly__no_rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__no_rhs_dollar__no_round {
+    ( $i:ident ) => { count(i) };
+    //~^ ERROR cannot find function `count` in this scope
+    //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__rhs_dollar__round {
+    ( $( $i:ident ),* ) => { count($i) };
+    //~^ ERROR variable 'i' is still repeating at this depth
+}
+
+macro_rules! no_curly__rhs_dollar__no_round {
+    ( $i:ident ) => { count($i) };
+    //~^ ERROR cannot find function `count` in this scope
+}
+
+// Other scenarios
+
+macro_rules! dollar_dollar_in_the_lhs {
+    ( $$ $a:ident ) => {
+    //~^ ERROR unexpected token: $
+    };
+}
+
+macro_rules! extra_garbage_after_metavar {
+    ( $( $i:ident ),* ) => {
+        ${count() a b c}
+        //~^ ERROR unexpected token: a
+        //~| ERROR expected expression, found `$`
+        ${count(i a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i, 1 a b c)}
+        //~^ ERROR unexpected token: a
+        ${count(i) a b c}
+        //~^ ERROR unexpected token: a
+
+        ${ignore(i) a b c}
+        //~^ ERROR unexpected token: a
+        ${ignore(i a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+
+        ${index() a b c}
+        //~^ ERROR unexpected token: a
+        ${index(1 a b c)}
+        //~^ ERROR unexpected token: a
+    };
+}
+
+const IDX: usize = 1;
+macro_rules! metavar_depth_is_not_literal {
+    ( $( $i:ident ),* ) => { ${ index(IDX) } };
+    //~^ ERROR meta-variable expression depth must be a literal
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_in_the_lhs {
+    ( ${ length() } ) => {
+        //~^ ERROR unexpected token: {
+        //~| ERROR expected one of: `*`, `+`, or `?`
+    };
+}
+
+macro_rules! metavar_token_without_ident {
+    ( $( $i:ident ),* ) => { ${ ignore() } };
+    //~^ ERROR expected identifier
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_with_literal_suffix {
+    ( $( $i:ident ),* ) => { ${ index(1u32) } };
+    //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_without_parens {
+    ( $( $i:ident ),* ) => { ${ count{i} } };
+    //~^ ERROR meta-variable expression parameter must be wrapped in parentheses
+    //~| ERROR expected expression, found `$`
+}
+
+macro_rules! open_brackets_without_tokens {
+    ( $( $i:ident ),* ) => { ${ {} } };
+    //~^ ERROR expected expression, found `$`
+    //~| ERROR expected identifier
+}
+
+macro_rules! unknown_count_ident {
+    ( $( $i:ident )* ) => {
+        ${count(foo)}
+        //~^ ERROR variable `foo` is not recognized in meta-variable expression
+    };
+}
+
+macro_rules! unknown_ignore_ident {
+    ( $( $i:ident )* ) => {
+        ${ignore(bar)}
+        //~^ ERROR variable `bar` is not recognized in meta-variable expression
+    };
+}
+
+macro_rules! unknown_metavar {
+    ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+    //~^ ERROR unrecognized meta-variable expression
+    //~| ERROR expected expression
+}
+
+fn main() {
+    curly__no_rhs_dollar__round!(a, b, c);
+    curly__no_rhs_dollar__no_round!(a);
+    curly__rhs_dollar__round!(a, b, c);
+    curly__rhs_dollar__no_round!(a);
+    no_curly__no_rhs_dollar__round!(a, b, c);
+    no_curly__no_rhs_dollar__no_round!(a);
+    no_curly__rhs_dollar__round!(a, b, c);
+    no_curly__rhs_dollar__no_round!(a);
+    //~^ ERROR cannot find value `a` in this scope
+
+    extra_garbage_after_metavar!(a);
+    metavar_depth_is_not_literal!(a);
+    metavar_token_without_ident!(a);
+    metavar_with_literal_suffix!(a);
+    metavar_without_parens!(a);
+    open_brackets_without_tokens!(a);
+    unknown_count_ident!(a);
+    unknown_ignore_ident!(a);
+    unknown_metavar!(a);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
new file mode 100644
index 00000000000..a6cff95fd91
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -0,0 +1,385 @@
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:17:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                                 ^^^^^ - help: try removing `$`
+
+error: expected identifier, found `$`
+  --> $DIR/syntax-errors.rs:23:26
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                          ^^^^^ - help: try removing `$`
+
+error: unexpected token: $
+  --> $DIR/syntax-errors.rs:53:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:53:8
+   |
+LL |     ( $$ $a:ident ) => {
+   |        ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:60:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:60:19
+   |
+LL |         ${count() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:63:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:63:19
+   |
+LL |         ${count(i a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:65:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:65:22
+   |
+LL |         ${count(i, 1 a b c)}
+   |                      ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:67:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:67:20
+   |
+LL |         ${count(i) a b c}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:70:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:70:21
+   |
+LL |         ${ignore(i) a b c}
+   |                     ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:72:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:72:20
+   |
+LL |         ${ignore(i a b c)}
+   |                    ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:75:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:75:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:77:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:77:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:80:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:80:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:82:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:82:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: meta-variable expression depth must be a literal
+  --> $DIR/syntax-errors.rs:89:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                                 ^^^^^
+
+error: unexpected token: {
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected one of: `*`, `+`, or `?`
+  --> $DIR/syntax-errors.rs:95:8
+   |
+LL |     ( ${ length() } ) => {
+   |        ^^^^^^^^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:102:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                                 ^^^^^^
+
+error: only unsuffixes integer literals are supported in meta-variable expressions
+  --> $DIR/syntax-errors.rs:108:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                                 ^^^^^
+
+error: meta-variable expression parameter must be wrapped in parentheses
+  --> $DIR/syntax-errors.rs:114:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                                 ^^^^^
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:120:31
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                               ^^^^^^
+
+error: unrecognized meta-variable expression
+  --> $DIR/syntax-errors.rs:140:33
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+
+error: `count` can not be placed inside the inner-most repetition
+  --> $DIR/syntax-errors.rs:12:24
+   |
+LL |     ( $i:ident ) => { ${ count(i) } };
+   |                        ^^^^^^^^^^^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:17:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count($i) } };
+   |                              ^ expected expression
+...
+LL |     curly__rhs_dollar__round!(a, b, c);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:23:23
+   |
+LL |     ( $i:ident ) => { ${ count($i) } };
+   |                       ^ expected expression
+...
+LL |     curly__rhs_dollar__no_round!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable 'i' is still repeating at this depth
+  --> $DIR/syntax-errors.rs:41:36
+   |
+LL |     ( $( $i:ident ),* ) => { count($i) };
+   |                                    ^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:60:9
+   |
+LL |         ${count() a b c}
+   |         ^ expected expression
+...
+LL |     extra_garbage_after_metavar!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:89:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
+   |                              ^ expected expression
+...
+LL |     metavar_depth_is_not_literal!(a);
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:102:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
+   |                              ^ expected expression
+...
+LL |     metavar_token_without_ident!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:108:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
+   |                              ^ expected expression
+...
+LL |     metavar_with_literal_suffix!(a);
+   |     ------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:114:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
+   |                              ^ expected expression
+...
+LL |     metavar_without_parens!(a);
+   |     -------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:120:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                              ^ expected expression
+...
+LL |     open_brackets_without_tokens!(a);
+   |     -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable `foo` is not recognized in meta-variable expression
+  --> $DIR/syntax-errors.rs:127:17
+   |
+LL |         ${count(foo)}
+   |                 ^^^
+
+error: variable `bar` is not recognized in meta-variable expression
+  --> $DIR/syntax-errors.rs:134:18
+   |
+LL |         ${ignore(bar)}
+   |                  ^^^
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:140:30
+   |
+LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+   |                              ^ expected expression
+...
+LL |     unknown_metavar!(a);
+   |     ------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:29:36
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                                    ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+  --> $DIR/syntax-errors.rs:35:29
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                             ^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `a` in this scope
+  --> $DIR/syntax-errors.rs:153:37
+   |
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |                                     ^ not found in this scope
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:29:30
+   |
+LL |     ( $( $i:ident ),* ) => { count(i) };
+   |                              ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__round!(a, b, c);
+   |     ---------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:35:23
+   |
+LL |     ( $i:ident ) => { count(i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__no_rhs_dollar__no_round!(a);
+   |     ------------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+  --> $DIR/syntax-errors.rs:46:23
+   |
+LL |     ( $i:ident ) => { count($i) };
+   |                       ^^^^^ not found in this scope
+...
+LL |     no_curly__rhs_dollar__no_round!(a);
+   |     ---------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 40 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/macros/same-sequence-span.rs b/tests/ui/macros/same-sequence-span.rs
new file mode 100644
index 00000000000..e0bb4d98525
--- /dev/null
+++ b/tests/ui/macros/same-sequence-span.rs
@@ -0,0 +1,22 @@
+// aux-build:proc_macro_sequence.rs
+
+// Regression test for issue #62831: Check that multiple sequences with the same span in the
+// left-hand side of a macro definition behave as if they had unique spans, and in particular that
+// they don't crash the compiler.
+
+#![allow(unused_macros)]
+
+extern crate proc_macro_sequence;
+
+// When ignoring spans, this macro has the same macro definition as `generated_foo` in
+// `proc_macro_sequence.rs`.
+macro_rules! manual_foo {
+    (1 $x:expr $($y:tt,)*   //~ERROR `$x:expr` may be followed by `$y:tt`
+               $(= $z:tt)*  //~ERROR `$x:expr` may be followed by `=`
+    ) => {};
+}
+
+proc_macro_sequence::make_foo!(); //~ERROR `$x:expr` may be followed by `$y:tt`
+                                  //~^ERROR `$x:expr` may be followed by `=`
+
+fn main() {}
diff --git a/tests/ui/macros/same-sequence-span.stderr b/tests/ui/macros/same-sequence-span.stderr
new file mode 100644
index 00000000000..bdd191e8ed6
--- /dev/null
+++ b/tests/ui/macros/same-sequence-span.stderr
@@ -0,0 +1,43 @@
+error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
+  --> $DIR/same-sequence-span.rs:14:18
+   |
+LL |     (1 $x:expr $($y:tt,)*
+   |                  ^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
+  --> $DIR/same-sequence-span.rs:15:18
+   |
+LL |                $(= $z:tt)*
+   |                  ^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+
+error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments
+  --> $DIR/same-sequence-span.rs:19:1
+   |
+LL |   proc_macro_sequence::make_foo!();
+   |   ^-------------------------------
+   |   |
+   |  _in this macro invocation
+   | |
+LL | |
+LL | |
+LL | | fn main() {}
+   | |_________________________________^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+   = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `$x:expr` may be followed by `=`, which is not allowed for `expr` fragments
+  --> $DIR/same-sequence-span.rs:19:1
+   |
+LL | proc_macro_sequence::make_foo!();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed after `expr` fragments
+   |
+   = note: allowed there are: `=>`, `,` or `;`
+   = note: this error originates in the macro `proc_macro_sequence::make_foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/macros/semi-after-macro-ty.rs b/tests/ui/macros/semi-after-macro-ty.rs
new file mode 100644
index 00000000000..f83ace8fada
--- /dev/null
+++ b/tests/ui/macros/semi-after-macro-ty.rs
@@ -0,0 +1,8 @@
+// run-pass
+macro_rules! foo {
+    ($t:ty; $p:path;) => {}
+}
+
+fn main() {
+    foo!(i32; i32;);
+}
diff --git a/tests/ui/macros/span-covering-argument-1.rs b/tests/ui/macros/span-covering-argument-1.rs
new file mode 100644
index 00000000000..9b9506c80b1
--- /dev/null
+++ b/tests/ui/macros/span-covering-argument-1.rs
@@ -0,0 +1,13 @@
+macro_rules! bad {
+    ($s:ident whatever) => {
+        {
+            let $s = 0;
+            *&mut $s = 0;
+            //~^ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable [E0596]
+        }
+    }
+}
+
+fn main() {
+    bad!(foo whatever);
+}
diff --git a/tests/ui/macros/span-covering-argument-1.stderr b/tests/ui/macros/span-covering-argument-1.stderr
new file mode 100644
index 00000000000..e57347b362d
--- /dev/null
+++ b/tests/ui/macros/span-covering-argument-1.stderr
@@ -0,0 +1,18 @@
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/span-covering-argument-1.rs:5:14
+   |
+LL |             *&mut $s = 0;
+   |              ^^^^^^^ cannot borrow as mutable
+...
+LL |     bad!(foo whatever);
+   |     ------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `bad` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider changing this to be mutable
+   |
+LL |             let mut $s = 0;
+   |                 +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/macros/stmt_expr_attr_macro_parse.rs b/tests/ui/macros/stmt_expr_attr_macro_parse.rs
new file mode 100644
index 00000000000..570191d2c90
--- /dev/null
+++ b/tests/ui/macros/stmt_expr_attr_macro_parse.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![allow(unused_macro_rules)]
+
+macro_rules! m {
+    ($e:expr) => {
+        "expr includes attr"
+    };
+    (#[$attr:meta] $e:expr) => {
+        "expr excludes attr"
+    }
+}
+
+macro_rules! n {
+    (#[$attr:meta] $e:expr) => {
+        "expr excludes attr"
+    };
+    ($e:expr) => {
+        "expr includes attr"
+    }
+}
+
+fn main() {
+    assert_eq!(m!(#[attr] 1), "expr includes attr");
+    assert_eq!(n!(#[attr] 1), "expr excludes attr");
+}
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
new file mode 100644
index 00000000000..5cd217df6fc
--- /dev/null
+++ b/tests/ui/macros/stringify.rs
@@ -0,0 +1,889 @@
+// run-pass
+// edition:2021
+// compile-flags: --test
+
+#![feature(async_closure)]
+#![feature(box_patterns)]
+#![feature(box_syntax)]
+#![feature(const_trait_impl)]
+#![feature(decl_macro)]
+#![feature(generators)]
+#![feature(more_qualified_paths)]
+#![feature(raw_ref_op)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(type_ascription)]
+#![deny(unused_macros)]
+
+macro_rules! stringify_block {
+    ($block:block) => {
+        stringify!($block)
+    };
+}
+
+macro_rules! stringify_expr {
+    ($expr:expr) => {
+        stringify!($expr)
+    };
+}
+
+macro_rules! stringify_item {
+    ($item:item) => {
+        stringify!($item)
+    };
+}
+
+macro_rules! stringify_meta {
+    ($meta:meta) => {
+        stringify!($meta)
+    };
+}
+
+macro_rules! stringify_pat {
+    ($pat:pat) => {
+        stringify!($pat)
+    };
+}
+
+macro_rules! stringify_path {
+    ($path:path) => {
+        stringify!($path)
+    };
+}
+
+macro_rules! stringify_stmt {
+    ($stmt:stmt) => {
+        stringify!($stmt)
+    };
+}
+
+macro_rules! stringify_ty {
+    ($ty:ty) => {
+        stringify!($ty)
+    };
+}
+
+macro_rules! stringify_vis {
+    ($vis:vis) => {
+        stringify!($vis)
+    };
+}
+
+#[test]
+fn test_block() {
+    assert_eq!(stringify_block!({}), "{}");
+    assert_eq!(stringify_block!({ true }), "{ true }");
+    assert_eq!(stringify_block!({ return }), "{ return }");
+    assert_eq!(
+        stringify_block!({
+            return;
+        }),
+        "{ return; }",
+    );
+    assert_eq!(
+        stringify_block!({
+            let _;
+            true
+        }),
+        "{ let _; true }",
+    );
+}
+
+#[test]
+fn test_expr() {
+    // ExprKind::Box
+    assert_eq!(stringify_expr!(box expr), "box expr");
+
+    // ExprKind::Array
+    assert_eq!(stringify_expr!([]), "[]");
+    assert_eq!(stringify_expr!([true]), "[true]");
+    assert_eq!(stringify_expr!([true,]), "[true]");
+    assert_eq!(stringify_expr!([true, true]), "[true, true]");
+
+    // ExprKind::Call
+    assert_eq!(stringify_expr!(f()), "f()");
+    assert_eq!(stringify_expr!(f::<u8>()), "f::<u8>()");
+    assert_eq!(stringify_expr!(f::<1>()), "f::<1>()");
+    assert_eq!(stringify_expr!(f::<'a, u8, 1>()), "f::<'a, u8, 1>()");
+    assert_eq!(stringify_expr!(f(true)), "f(true)");
+    assert_eq!(stringify_expr!(f(true,)), "f(true)");
+    assert_eq!(stringify_expr!(()()), "()()");
+
+    // ExprKind::MethodCall
+    assert_eq!(stringify_expr!(x.f()), "x.f()");
+    assert_eq!(stringify_expr!(x.f::<u8>()), "x.f::<u8>()");
+
+    // ExprKind::Tup
+    assert_eq!(stringify_expr!(()), "()");
+    assert_eq!(stringify_expr!((true,)), "(true,)");
+    assert_eq!(stringify_expr!((true, false)), "(true, false)");
+    assert_eq!(stringify_expr!((true, false,)), "(true, false)");
+
+    // ExprKind::Binary
+    assert_eq!(stringify_expr!(true || false), "true || false");
+    assert_eq!(stringify_expr!(true || false && false), "true || false && false");
+
+    // ExprKind::Unary
+    assert_eq!(stringify_expr!(*expr), "*expr");
+    assert_eq!(stringify_expr!(!expr), "!expr");
+    assert_eq!(stringify_expr!(-expr), "-expr");
+
+    // ExprKind::Lit
+    assert_eq!(stringify_expr!('x'), "'x'");
+    assert_eq!(stringify_expr!(1_000_i8), "1_000_i8");
+    assert_eq!(stringify_expr!(1.00000000000000001), "1.00000000000000001");
+
+    // ExprKind::Cast
+    assert_eq!(stringify_expr!(expr as T), "expr as T");
+    assert_eq!(stringify_expr!(expr as T<u8>), "expr as T<u8>");
+
+    // ExprKind::Type
+    assert_eq!(stringify_expr!(expr: T), "expr: T");
+    assert_eq!(stringify_expr!(expr: T<u8>), "expr: T<u8>");
+
+    // ExprKind::If
+    assert_eq!(stringify_expr!(if true {}), "if true {}");
+    assert_eq!(
+        stringify_expr!(if true {
+        } else {
+        }),
+        "if true {} else {}",
+    );
+    assert_eq!(
+        stringify_expr!(if let true = true {
+        } else {
+        }),
+        "if let true = true {} else {}",
+    );
+    assert_eq!(
+        stringify_expr!(if true {
+        } else if false {
+        }),
+        "if true {} else if false {}",
+    );
+    assert_eq!(
+        stringify_expr!(if true {
+        } else if false {
+        } else {
+        }),
+        "if true {} else if false {} else {}",
+    );
+    assert_eq!(
+        stringify_expr!(if true {
+            return;
+        } else if false {
+            0
+        } else {
+            0
+        }),
+        "if true { return; } else if false { 0 } else { 0 }",
+    );
+
+    // ExprKind::While
+    assert_eq!(stringify_expr!(while true {}), "while true {}");
+    assert_eq!(stringify_expr!('a: while true {}), "'a: while true {}");
+    assert_eq!(stringify_expr!(while let true = true {}), "while let true = true {}");
+
+    // ExprKind::ForLoop
+    assert_eq!(stringify_expr!(for _ in x {}), "for _ in x {}");
+    assert_eq!(stringify_expr!('a: for _ in x {}), "'a: for _ in x {}");
+
+    // ExprKind::Loop
+    assert_eq!(stringify_expr!(loop {}), "loop {}");
+    assert_eq!(stringify_expr!('a: loop {}), "'a: loop {}");
+
+    // ExprKind::Match
+    assert_eq!(stringify_expr!(match self {}), "match self {}");
+    assert_eq!(
+        stringify_expr!(match self {
+            Ok => 1,
+        }),
+        "match self { Ok => 1, }",
+    );
+    assert_eq!(
+        stringify_expr!(match self {
+            Ok => 1,
+            Err => 0,
+        }),
+        "match self { Ok => 1, Err => 0, }",
+    );
+
+    // ExprKind::Closure
+    assert_eq!(stringify_expr!(|| {}), "|| {}");
+    assert_eq!(stringify_expr!(|x| {}), "|x| {}");
+    assert_eq!(stringify_expr!(|x: u8| {}), "|x: u8| {}");
+    assert_eq!(stringify_expr!(|| ()), "|| ()");
+    assert_eq!(stringify_expr!(move || self), "move || self");
+    assert_eq!(stringify_expr!(async || self), "async || self");
+    assert_eq!(stringify_expr!(async move || self), "async move || self");
+    assert_eq!(stringify_expr!(static || self), "static || self");
+    assert_eq!(stringify_expr!(static move || self), "static move || self");
+    #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149
+    assert_eq!(
+        stringify_expr!(static async || self),
+        "static async || self",
+    );
+    #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5149
+    assert_eq!(
+        stringify_expr!(static async move || self),
+        "static async move || self",
+    );
+    assert_eq!(stringify_expr!(|| -> u8 { self }), "|| -> u8 { self }");
+    assert_eq!(stringify_expr!(1 + || {}), "1 + (|| {})"); // ??
+
+    // ExprKind::Block
+    assert_eq!(stringify_expr!({}), "{}");
+    assert_eq!(stringify_expr!(unsafe {}), "unsafe {}");
+    assert_eq!(stringify_expr!('a: {}), "'a: {}");
+    assert_eq!(
+        stringify_expr!(
+            #[attr]
+            {}
+        ),
+        "#[attr] {}",
+    );
+    assert_eq!(
+        stringify_expr!(
+            {
+                #![attr]
+            }
+        ),
+        "{\n\
+        \x20   #![attr]\n\
+        }",
+    );
+
+    // ExprKind::Async
+    assert_eq!(stringify_expr!(async {}), "async {}");
+    assert_eq!(stringify_expr!(async move {}), "async move {}");
+
+    // ExprKind::Await
+    assert_eq!(stringify_expr!(expr.await), "expr.await");
+
+    // ExprKind::TryBlock
+    assert_eq!(stringify_expr!(try {}), "try {}");
+
+    // ExprKind::Assign
+    assert_eq!(stringify_expr!(expr = true), "expr = true");
+
+    // ExprKind::AssignOp
+    assert_eq!(stringify_expr!(expr += true), "expr += true");
+
+    // ExprKind::Field
+    assert_eq!(stringify_expr!(expr.field), "expr.field");
+    assert_eq!(stringify_expr!(expr.0), "expr.0");
+
+    // ExprKind::Index
+    assert_eq!(stringify_expr!(expr[true]), "expr[true]");
+
+    // ExprKind::Range
+    assert_eq!(stringify_expr!(..), "..");
+    assert_eq!(stringify_expr!(..hi), "..hi");
+    assert_eq!(stringify_expr!(lo..), "lo..");
+    assert_eq!(stringify_expr!(lo..hi), "lo..hi");
+    assert_eq!(stringify_expr!(..=hi), "..=hi");
+    assert_eq!(stringify_expr!(lo..=hi), "lo..=hi");
+    assert_eq!(stringify_expr!(-2..=-1), "-2..=-1");
+
+    // ExprKind::Path
+    assert_eq!(stringify_expr!(thing), "thing");
+    assert_eq!(stringify_expr!(m::thing), "m::thing");
+    assert_eq!(stringify_expr!(self::thing), "self::thing");
+    assert_eq!(stringify_expr!(crate::thing), "crate::thing");
+    assert_eq!(stringify_expr!(Self::thing), "Self::thing");
+    assert_eq!(stringify_expr!(<Self as T>::thing), "<Self as T>::thing");
+    assert_eq!(stringify_expr!(Self::<'static>), "Self::<'static>");
+
+    // ExprKind::AddrOf
+    assert_eq!(stringify_expr!(&expr), "&expr");
+    assert_eq!(stringify_expr!(&mut expr), "&mut expr");
+    assert_eq!(stringify_expr!(&raw const expr), "&raw const expr");
+    assert_eq!(stringify_expr!(&raw mut expr), "&raw mut expr");
+
+    // ExprKind::Break
+    assert_eq!(stringify_expr!(break), "break");
+    assert_eq!(stringify_expr!(break 'a), "break 'a");
+    assert_eq!(stringify_expr!(break true), "break true");
+    assert_eq!(stringify_expr!(break 'a true), "break 'a true");
+
+    // ExprKind::Continue
+    assert_eq!(stringify_expr!(continue), "continue");
+    assert_eq!(stringify_expr!(continue 'a), "continue 'a");
+
+    // ExprKind::Ret
+    assert_eq!(stringify_expr!(return), "return");
+    assert_eq!(stringify_expr!(return true), "return true");
+
+    // ExprKind::MacCall
+    assert_eq!(stringify_expr!(mac!(...)), "mac!(...)");
+    assert_eq!(stringify_expr!(mac![...]), "mac![...]");
+    assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }");
+
+    // ExprKind::Struct
+    assert_eq!(stringify_expr!(Struct {}), "Struct {}");
+    #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
+    assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}");
+    assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }");
+    assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }");
+    assert_eq!(stringify_expr!(Struct { x }), "Struct { x }");
+    assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }");
+    assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }");
+    assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }");
+    assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }");
+    assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }");
+
+    // ExprKind::Repeat
+    assert_eq!(stringify_expr!([(); 0]), "[(); 0]");
+
+    // ExprKind::Paren
+    assert_eq!(stringify_expr!((expr)), "(expr)");
+
+    // ExprKind::Try
+    assert_eq!(stringify_expr!(expr?), "expr?");
+
+    // ExprKind::Yield
+    assert_eq!(stringify_expr!(yield), "yield");
+    assert_eq!(stringify_expr!(yield true), "yield true");
+}
+
+#[test]
+fn test_item() {
+    // ItemKind::ExternCrate
+    assert_eq!(
+        stringify_item!(
+            extern crate std;
+        ),
+        "extern crate std;",
+    );
+    assert_eq!(
+        stringify_item!(
+            pub extern crate self as std;
+        ),
+        "pub extern crate self as std;",
+    );
+
+    // ItemKind::Use
+    assert_eq!(
+        stringify_item!(
+            pub use crate::{a, b::c};
+        ),
+        "pub use crate::{a, b::c};",
+    );
+
+    // ItemKind::Static
+    assert_eq!(
+        stringify_item!(
+            pub static S: () = {};
+        ),
+        "pub static S: () = {};",
+    );
+    assert_eq!(
+        stringify_item!(
+            static mut S: () = {};
+        ),
+        "static mut S: () = {};",
+    );
+    assert_eq!(
+        stringify_item!(
+            static S: ();
+        ),
+        "static S: ();",
+    );
+    assert_eq!(
+        stringify_item!(
+            static mut S: ();
+        ),
+        "static mut S: ();",
+    );
+
+    // ItemKind::Const
+    assert_eq!(
+        stringify_item!(
+            pub const S: () = {};
+        ),
+        "pub const S: () = {};",
+    );
+    assert_eq!(
+        stringify_item!(
+            const S: ();
+        ),
+        "const S: ();",
+    );
+
+    // ItemKind::Fn
+    assert_eq!(
+        stringify_item!(
+            pub default const async unsafe extern "C" fn f() {}
+        ),
+        "pub default const async unsafe extern \"C\" fn f() {}",
+    );
+
+    // ItemKind::Mod
+    assert_eq!(
+        stringify_item!(
+            pub mod m;
+        ),
+        "pub mod m;",
+    );
+    assert_eq!(
+        stringify_item!(
+            mod m {}
+        ),
+        "mod m {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            unsafe mod m;
+        ),
+        "unsafe mod m;",
+    );
+    assert_eq!(
+        stringify_item!(
+            unsafe mod m {}
+        ),
+        "unsafe mod m {}",
+    );
+
+    // ItemKind::ForeignMod
+    assert_eq!(
+        stringify_item!(
+            extern "C" {}
+        ),
+        "extern \"C\" {}",
+    );
+    #[rustfmt::skip]
+    assert_eq!(
+        stringify_item!(
+            pub extern "C" {}
+        ),
+        "extern \"C\" {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            unsafe extern "C++" {}
+        ),
+        "unsafe extern \"C++\" {}",
+    );
+
+    // ItemKind::TyAlias
+    #[rustfmt::skip]
+    assert_eq!(
+        stringify_item!(
+            pub default type Type<'a>: Bound
+            where
+                Self: 'a,
+            = T;
+        ),
+        "pub default type Type<'a>: Bound where Self: 'a = T;",
+    );
+
+    // ItemKind::Enum
+    assert_eq!(
+        stringify_item!(
+            pub enum Void {}
+        ),
+        "pub enum Void {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            enum Empty {
+                Unit,
+                Tuple(),
+                Struct {},
+            }
+        ),
+        "enum Empty { Unit, Tuple(), Struct {}, }",
+    );
+    assert_eq!(
+        stringify_item!(
+            enum Enum<T>
+            where
+                T: 'a,
+            {
+                Unit,
+                Tuple(T),
+                Struct { t: T },
+            }
+        ),
+        "enum Enum<T> where T: 'a {\n\
+        \x20   Unit,\n\
+        \x20   Tuple(T),\n\
+        \x20   Struct {\n\
+        \x20       t: T,\n\
+        \x20   },\n\
+        }",
+    );
+
+    // ItemKind::Struct
+    assert_eq!(
+        stringify_item!(
+            pub struct Unit;
+        ),
+        "pub struct Unit;",
+    );
+    assert_eq!(
+        stringify_item!(
+            struct Tuple();
+        ),
+        "struct Tuple();",
+    );
+    assert_eq!(
+        stringify_item!(
+            struct Tuple(T);
+        ),
+        "struct Tuple(T);",
+    );
+    assert_eq!(
+        stringify_item!(
+            struct Struct {}
+        ),
+        "struct Struct {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            struct Struct<T>
+            where
+                T: 'a,
+            {
+                t: T,
+            }
+        ),
+        "struct Struct<T> where T: 'a {\n\
+        \x20   t: T,\n\
+        }",
+    );
+
+    // ItemKind::Union
+    assert_eq!(
+        stringify_item!(
+            pub union Union {}
+        ),
+        "pub union Union {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            union Union<T> where T: 'a {
+                t: T,
+            }
+        ),
+        "union Union<T> where T: 'a {\n\
+        \x20   t: T,\n\
+        }",
+    );
+
+    // ItemKind::Trait
+    assert_eq!(
+        stringify_item!(
+            pub unsafe auto trait Send {}
+        ),
+        "pub unsafe auto trait Send {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            trait Trait<'a>: Sized
+            where
+                Self: 'a,
+            {
+            }
+        ),
+        "trait Trait<'a>: Sized where Self: 'a {}",
+    );
+
+    // ItemKind::TraitAlias
+    assert_eq!(
+        stringify_item!(
+            pub trait Trait<T> = Sized where T: 'a;
+        ),
+        "pub trait Trait<T> = Sized where T: 'a;",
+    );
+
+    // ItemKind::Impl
+    assert_eq!(
+        stringify_item!(
+            pub impl Struct {}
+        ),
+        "pub impl Struct {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            impl<T> Struct<T> {}
+        ),
+        "impl<T> Struct<T> {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            pub impl Trait for Struct {}
+        ),
+        "pub impl Trait for Struct {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            impl<T> const Trait for T {}
+        ),
+        "impl<T> const Trait for T {}",
+    );
+    assert_eq!(
+        stringify_item!(
+            impl ~const Struct {}
+        ),
+        "impl Struct {}", // FIXME
+    );
+
+    // ItemKind::MacCall
+    assert_eq!(stringify_item!(mac!(...);), "mac!(...);");
+    assert_eq!(stringify_item!(mac![...];), "mac![...];");
+    assert_eq!(stringify_item!(mac! { ... }), "mac! { ... }");
+
+    // ItemKind::MacroDef
+    assert_eq!(
+        stringify_item!(
+            macro_rules! stringify {
+                () => {};
+            }
+        ),
+        "macro_rules! stringify { () => {} ; }", // FIXME
+    );
+    assert_eq!(
+        stringify_item!(
+            pub macro stringify() {}
+        ),
+        "pub macro stringify { () => {} }",
+    );
+}
+
+#[test]
+fn test_meta() {
+    assert_eq!(stringify_meta!(k), "k");
+    assert_eq!(stringify_meta!(k = "v"), "k = \"v\"");
+    assert_eq!(stringify_meta!(list(k1, k2 = "v")), "list(k1, k2 = \"v\")");
+    assert_eq!(stringify_meta!(serde::k), "serde::k");
+}
+
+#[test]
+fn test_pat() {
+    // PatKind::Wild
+    assert_eq!(stringify_pat!(_), "_");
+
+    // PatKind::Ident
+    assert_eq!(stringify_pat!(_x), "_x");
+    assert_eq!(stringify_pat!(ref _x), "ref _x");
+    assert_eq!(stringify_pat!(mut _x), "mut _x");
+    assert_eq!(stringify_pat!(ref mut _x), "ref mut _x");
+    assert_eq!(stringify_pat!(ref mut _x @ _), "ref mut _x @ _");
+
+    // PatKind::Struct
+    assert_eq!(stringify_pat!(Struct {}), "Struct {}");
+    assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {}");
+    assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {}");
+    assert_eq!(stringify_pat!(Struct { x }), "Struct { x }");
+    assert_eq!(stringify_pat!(Struct { x: _x }), "Struct { x: _x }");
+    assert_eq!(stringify_pat!(Struct { .. }), "Struct { .. }");
+    assert_eq!(stringify_pat!(Struct { x, .. }), "Struct { x, .. }");
+    assert_eq!(stringify_pat!(Struct { x: _x, .. }), "Struct { x: _x, .. }");
+    #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
+    assert_eq!(
+        stringify_pat!(<Struct as Trait>::Type {}),
+        "<Struct as Trait>::Type {}",
+    );
+
+    // PatKind::TupleStruct
+    assert_eq!(stringify_pat!(Tuple()), "Tuple()");
+    assert_eq!(stringify_pat!(Tuple::<u8>()), "Tuple::<u8>()");
+    assert_eq!(stringify_pat!(Tuple::<'static>()), "Tuple::<'static>()");
+    assert_eq!(stringify_pat!(Tuple(x)), "Tuple(x)");
+    assert_eq!(stringify_pat!(Tuple(..)), "Tuple(..)");
+    assert_eq!(stringify_pat!(Tuple(x, ..)), "Tuple(x, ..)");
+    assert_eq!(stringify_pat!(<Struct as Trait>::Type()), "<Struct as Trait>::Type()");
+
+    // PatKind::Or
+    assert_eq!(stringify_pat!(true | false), "true | false");
+    assert_eq!(stringify_pat!(| true), "true");
+    assert_eq!(stringify_pat!(|true| false), "true | false");
+
+    // PatKind::Path
+    assert_eq!(stringify_pat!(crate::Path), "crate::Path");
+    assert_eq!(stringify_pat!(Path::<u8>), "Path::<u8>");
+    assert_eq!(stringify_pat!(Path::<'static>), "Path::<'static>");
+    assert_eq!(stringify_pat!(<Struct as Trait>::Type), "<Struct as Trait>::Type");
+
+    // PatKind::Tuple
+    assert_eq!(stringify_pat!(()), "()");
+    assert_eq!(stringify_pat!((true,)), "(true,)");
+    assert_eq!(stringify_pat!((true, false)), "(true, false)");
+
+    // PatKind::Box
+    assert_eq!(stringify_pat!(box pat), "box pat");
+
+    // PatKind::Ref
+    assert_eq!(stringify_pat!(&pat), "&pat");
+    assert_eq!(stringify_pat!(&mut pat), "&mut pat");
+
+    // PatKind::Lit
+    assert_eq!(stringify_pat!(1_000_i8), "1_000_i8");
+
+    // PatKind::Range
+    assert_eq!(stringify_pat!(..1), "..1");
+    assert_eq!(stringify_pat!(0..), "0..");
+    assert_eq!(stringify_pat!(0..1), "0..1");
+    assert_eq!(stringify_pat!(0..=1), "0..=1");
+    assert_eq!(stringify_pat!(-2..=-1), "-2..=-1");
+
+    // PatKind::Slice
+    assert_eq!(stringify_pat!([]), "[]");
+    assert_eq!(stringify_pat!([true]), "[true]");
+    assert_eq!(stringify_pat!([true,]), "[true]");
+    assert_eq!(stringify_pat!([true, false]), "[true, false]");
+
+    // PatKind::Rest
+    assert_eq!(stringify_pat!(..), "..");
+
+    // PatKind::Paren
+    assert_eq!(stringify_pat!((pat)), "(pat)");
+
+    // PatKind::MacCall
+    assert_eq!(stringify_pat!(mac!(...)), "mac!(...)");
+    assert_eq!(stringify_pat!(mac![...]), "mac![...]");
+    assert_eq!(stringify_pat!(mac! { ... }), "mac! { ... }");
+}
+
+#[test]
+fn test_path() {
+    assert_eq!(stringify_path!(thing), "thing");
+    assert_eq!(stringify_path!(m::thing), "m::thing");
+    assert_eq!(stringify_path!(self::thing), "self::thing");
+    assert_eq!(stringify_path!(crate::thing), "crate::thing");
+    assert_eq!(stringify_path!(Self::thing), "Self::thing");
+    assert_eq!(stringify_path!(Self<'static>), "Self<'static>");
+    assert_eq!(stringify_path!(Self::<'static>), "Self<'static>");
+    assert_eq!(stringify_path!(Self()), "Self()");
+    assert_eq!(stringify_path!(Self() -> ()), "Self() -> ()");
+}
+
+#[test]
+fn test_stmt() {
+    // StmtKind::Local
+    assert_eq!(stringify_stmt!(let _), "let _;");
+    assert_eq!(stringify_stmt!(let x = true), "let x = true;");
+    assert_eq!(stringify_stmt!(let x: bool = true), "let x: bool = true;");
+
+    // StmtKind::Item
+    assert_eq!(
+        stringify_stmt!(
+            struct S;
+        ),
+        "struct S;",
+    );
+
+    // StmtKind::Expr
+    assert_eq!(stringify_stmt!(loop {}), "loop {}");
+
+    // StmtKind::Semi
+    assert_eq!(stringify_stmt!(1 + 1), "1 + 1;");
+
+    // StmtKind::Empty
+    assert_eq!(stringify_stmt!(;), ";");
+
+    // StmtKind::MacCall
+    assert_eq!(stringify_stmt!(mac!(...)), "mac!(...)");
+    assert_eq!(stringify_stmt!(mac![...]), "mac![...]");
+    assert_eq!(stringify_stmt!(mac! { ... }), "mac! { ... }");
+}
+
+#[test]
+fn test_ty() {
+    // TyKind::Slice
+    assert_eq!(stringify_ty!([T]), "[T]");
+
+    // TyKind::Array
+    assert_eq!(stringify_ty!([T; 0]), "[T; 0]");
+
+    // TyKind::Ptr
+    assert_eq!(stringify_ty!(*const T), "*const T");
+    assert_eq!(stringify_ty!(*mut T), "*mut T");
+
+    // TyKind::Ref
+    assert_eq!(stringify_ty!(&T), "&T");
+    assert_eq!(stringify_ty!(&mut T), "&mut T");
+    assert_eq!(stringify_ty!(&'a T), "&'a T");
+    assert_eq!(stringify_ty!(&'a mut T), "&'a mut T");
+
+    // TyKind::BareFn
+    assert_eq!(stringify_ty!(fn()), "fn()");
+    assert_eq!(stringify_ty!(fn() -> ()), "fn() -> ()");
+    assert_eq!(stringify_ty!(fn(u8)), "fn(u8)");
+    assert_eq!(stringify_ty!(fn(x: u8)), "fn(x: u8)");
+    #[rustfmt::skip]
+    assert_eq!(stringify_ty!(for<> fn()), "fn()");
+    assert_eq!(stringify_ty!(for<'a> fn()), "for<'a> fn()");
+
+    // TyKind::Never
+    assert_eq!(stringify_ty!(!), "!");
+
+    // TyKind::Tup
+    assert_eq!(stringify_ty!(()), "()");
+    assert_eq!(stringify_ty!((T,)), "(T,)");
+    assert_eq!(stringify_ty!((T, U)), "(T, U)");
+
+    // TyKind::Path
+    assert_eq!(stringify_ty!(T), "T");
+    assert_eq!(stringify_ty!(Ref<'a>), "Ref<'a>");
+    assert_eq!(stringify_ty!(PhantomData<T>), "PhantomData<T>");
+    assert_eq!(stringify_ty!(PhantomData::<T>), "PhantomData<T>");
+    assert_eq!(stringify_ty!(Fn() -> !), "Fn() -> !");
+    assert_eq!(stringify_ty!(Fn(u8) -> !), "Fn(u8) -> !");
+    assert_eq!(stringify_ty!(<Struct as Trait>::Type), "<Struct as Trait>::Type");
+
+    // TyKind::TraitObject
+    assert_eq!(stringify_ty!(dyn Send), "dyn Send");
+    assert_eq!(stringify_ty!(dyn Send + 'a), "dyn Send + 'a");
+    assert_eq!(stringify_ty!(dyn 'a + Send), "dyn 'a + Send");
+    assert_eq!(stringify_ty!(dyn ?Sized), "dyn ?Sized");
+    assert_eq!(stringify_ty!(dyn ~const Clone), "dyn Clone"); // FIXME
+    assert_eq!(stringify_ty!(dyn for<'a> Send), "dyn for<'a> Send");
+
+    // TyKind::ImplTrait
+    assert_eq!(stringify_ty!(impl Send), "impl Send");
+    assert_eq!(stringify_ty!(impl Send + 'a), "impl Send + 'a");
+    assert_eq!(stringify_ty!(impl 'a + Send), "impl 'a + Send");
+    assert_eq!(stringify_ty!(impl ?Sized), "impl ?Sized");
+    assert_eq!(stringify_ty!(impl ~const Clone), "impl Clone"); // FIXME
+    assert_eq!(stringify_ty!(impl for<'a> Send), "impl for<'a> Send");
+
+    // TyKind::Paren
+    assert_eq!(stringify_ty!((T)), "(T)");
+
+    // TyKind::Infer
+    assert_eq!(stringify_ty!(_), "_");
+
+    // TyKind::MacCall
+    assert_eq!(stringify_ty!(mac!(...)), "mac!(...)");
+    assert_eq!(stringify_ty!(mac![...]), "mac![...]");
+    assert_eq!(stringify_ty!(mac! { ... }), "mac! { ... }");
+}
+
+#[test]
+fn test_vis() {
+    // VisibilityKind::Public
+    assert_eq!(stringify_vis!(pub), "pub ");
+
+    // VisibilityKind::Restricted
+    assert_eq!(stringify_vis!(pub(crate)), "pub(crate) ");
+    assert_eq!(stringify_vis!(pub(self)), "pub(self) ");
+    assert_eq!(stringify_vis!(pub(super)), "pub(super) ");
+    assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) ");
+    assert_eq!(stringify_vis!(pub(in self)), "pub(in self) ");
+    assert_eq!(stringify_vis!(pub(in super)), "pub(in super) ");
+    assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) ");
+    assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) ");
+    assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) ");
+    assert_eq!(stringify_vis!(pub(in super::path::to)), "pub(in super::path::to) ");
+
+    // VisibilityKind::Inherited
+    // Directly calling `stringify_vis!()` does not work.
+    macro_rules! stringify_inherited_vis {
+        ($vis:vis struct) => {
+            stringify_vis!($vis)
+        };
+    }
+    assert_eq!(stringify_inherited_vis!(struct), "");
+}
diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs
new file mode 100644
index 00000000000..ae6de3c5046
--- /dev/null
+++ b/tests/ui/macros/syntax-error-recovery.rs
@@ -0,0 +1,18 @@
+macro_rules! values {
+    ($($token:ident($value:literal) $(as $inner:ty)? => $attr:meta,)*) => {
+        #[derive(Debug)]
+        pub enum TokenKind {
+            $(
+                #[$attr]
+                $token $($inner)? = $value,
+            )*
+        }
+    };
+}
+//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
+//~| ERROR macro expansion ignores token `(String)` and any following
+
+values!(STRING(1) as (String) => cfg(test),);
+//~^ ERROR expected one of `!` or `::`, found `<eof>`
+
+fn main() {}
diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr
new file mode 100644
index 00000000000..c42ee9b295e
--- /dev/null
+++ b/tests/ui/macros/syntax-error-recovery.stderr
@@ -0,0 +1,31 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found `(String)`
+  --> $DIR/syntax-error-recovery.rs:7:26
+   |
+LL |                 $token $($inner)? = $value,
+   |                          ^^^^^^ expected one of `(`, `,`, `=`, `{`, or `}`
+...
+LL | values!(STRING(1) as (String) => cfg(test),);
+   | -------------------------------------------- in this macro invocation
+   |
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+   = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: macro expansion ignores token `(String)` and any following
+  --> $DIR/syntax-error-recovery.rs:7:26
+   |
+LL |                 $token $($inner)? = $value,
+   |                          ^^^^^^
+...
+LL | values!(STRING(1) as (String) => cfg(test),);
+   | -------------------------------------------- caused by the macro expansion here
+   |
+   = note: the usage of `values!` is likely invalid in item context
+
+error: expected one of `!` or `::`, found `<eof>`
+  --> $DIR/syntax-error-recovery.rs:15:9
+   |
+LL | values!(STRING(1) as (String) => cfg(test),);
+   |         ^^^^^^ expected one of `!` or `::`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/syntax-extension-cfg.rs b/tests/ui/macros/syntax-extension-cfg.rs
new file mode 100644
index 00000000000..2e929fc1dfa
--- /dev/null
+++ b/tests/ui/macros/syntax-extension-cfg.rs
@@ -0,0 +1,24 @@
+// run-pass
+// compile-flags: --cfg foo --cfg qux="foo"
+
+
+pub fn main() {
+    // check
+    if ! cfg!(foo) { panic!() }
+    if   cfg!(not(foo)) { panic!() }
+
+    if ! cfg!(qux="foo") { panic!() }
+    if   cfg!(not(qux="foo")) { panic!() }
+
+    if ! cfg!(all(foo, qux="foo")) { panic!() }
+    if   cfg!(not(all(foo, qux="foo"))) { panic!() }
+    if   cfg!(all(not(all(foo, qux="foo")))) { panic!() }
+
+    if cfg!(not_a_cfg) { panic!() }
+    if cfg!(all(not_a_cfg, foo, qux="foo")) { panic!() }
+    if cfg!(all(not_a_cfg, foo, qux="foo")) { panic!() }
+    if ! cfg!(any(not_a_cfg, foo)) { panic!() }
+
+    if ! cfg!(not(not_a_cfg)) { panic!() }
+    if ! cfg!(all(not(not_a_cfg), foo, qux="foo")) { panic!() }
+}
diff --git a/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment b/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment
new file mode 100644
index 00000000000..d752015a4dc
--- /dev/null
+++ b/tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment
@@ -0,0 +1,7 @@
+/* this is for run-pass/syntax-extension-source-utils.rs */
+
+{
+    assert!(file!().ends_with("includeme.fragment"));
+    assert_eq!(line!(), 5u32);
+    format!("victory robot {}", line!())
+}
diff --git a/tests/ui/macros/syntax-extension-source-utils.rs b/tests/ui/macros/syntax-extension-source-utils.rs
new file mode 100644
index 00000000000..7e46260d516
--- /dev/null
+++ b/tests/ui/macros/syntax-extension-source-utils.rs
@@ -0,0 +1,37 @@
+// run-pass
+#![allow(stable_features)]
+
+// ignore-pretty issue #37195
+
+pub mod m1 {
+    pub mod m2 {
+        pub fn where_am_i() -> String {
+            (module_path!()).to_string()
+        }
+    }
+}
+
+macro_rules! indirect_line { () => ( line!() ) }
+
+pub fn main() {
+    assert_eq!(line!(), 17);
+    assert_eq!(column!(), 16);
+    assert_eq!(indirect_line!(), 19);
+    assert!((file!().ends_with("syntax-extension-source-utils.rs")));
+    assert_eq!(stringify!((2*3) + 5).to_string(), "(2 * 3) + 5".to_string());
+    assert!(include!("syntax-extension-source-utils-files/includeme.\
+                      fragment").to_string()
+           == "victory robot 6".to_string());
+
+    assert!(
+        include_str!("syntax-extension-source-utils-files/includeme.\
+                      fragment").to_string()
+        .starts_with("/* this is for "));
+    assert!(
+        include_bytes!("syntax-extension-source-utils-files/includeme.fragment")
+        [1] == (42 as u8)); // '*'
+    // The Windows tests are wrapped in an extra module for some reason
+    assert!((m1::m2::where_am_i().ends_with("m1::m2")));
+
+    assert_eq!((36, "(2 * 3) + 5"), (line!(), stringify!((2*3) + 5)));
+}
diff --git a/tests/ui/macros/trace-macro.rs b/tests/ui/macros/trace-macro.rs
new file mode 100644
index 00000000000..576120811db
--- /dev/null
+++ b/tests/ui/macros/trace-macro.rs
@@ -0,0 +1,6 @@
+// compile-flags: -Z trace-macros
+// build-pass (FIXME(62277): could be check-pass?)
+
+fn main() {
+    println!("Hello, World!");
+}
diff --git a/tests/ui/macros/trace-macro.stderr b/tests/ui/macros/trace-macro.stderr
new file mode 100644
index 00000000000..43272248c28
--- /dev/null
+++ b/tests/ui/macros/trace-macro.stderr
@@ -0,0 +1,9 @@
+note: trace_macro
+  --> $DIR/trace-macro.rs:5:5
+   |
+LL |     println!("Hello, World!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `println! { "Hello, World!" }`
+   = note: to `{ $crate :: io :: _print($crate :: format_args_nl! ("Hello, World!")) ; }`
+
diff --git a/tests/ui/macros/trace_faulty_macros.rs b/tests/ui/macros/trace_faulty_macros.rs
new file mode 100644
index 00000000000..b2fdd2e1965
--- /dev/null
+++ b/tests/ui/macros/trace_faulty_macros.rs
@@ -0,0 +1,43 @@
+// compile-flags: -Z trace-macros
+
+#![recursion_limit = "4"]
+
+macro_rules! my_faulty_macro {
+    () => {
+        my_faulty_macro!(bcd); //~ ERROR no rules
+    };
+}
+
+macro_rules! pat_macro {
+    () => {
+        pat_macro!(A{a:a, b:0, c:_, ..});
+    };
+    ($a:pat) => {
+        $a //~ ERROR expected expression
+    };
+}
+
+macro_rules! my_recursive_macro {
+    () => {
+        my_recursive_macro!(); //~ ERROR recursion limit
+    };
+}
+
+macro_rules! my_macro {
+    () => {};
+}
+
+fn main() {
+    my_faulty_macro!();
+    my_recursive_macro!();
+    test!();
+    non_exisiting!();
+    derive!(Debug);
+    let a = pat_macro!();
+}
+
+#[my_macro]
+fn use_bang_macro_as_attr() {}
+
+#[derive(Debug)] //~ ERROR `derive` may only be applied to `struct`s
+fn use_derive_macro_as_attr() {}
diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr
new file mode 100644
index 00000000000..21e47da0757
--- /dev/null
+++ b/tests/ui/macros/trace_faulty_macros.stderr
@@ -0,0 +1,85 @@
+error: no rules expected the token `bcd`
+  --> $DIR/trace_faulty_macros.rs:7:26
+   |
+LL | macro_rules! my_faulty_macro {
+   | ---------------------------- when calling this macro
+LL |     () => {
+LL |         my_faulty_macro!(bcd);
+   |                          ^^^ no rules expected this token in macro call
+...
+LL |     my_faulty_macro!();
+   |     ------------------ in this macro invocation
+   |
+   = note: while trying to match end of macro
+   = note: this error originates in the macro `my_faulty_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/trace_faulty_macros.rs:31:5
+   |
+LL |     my_faulty_macro!();
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `my_faulty_macro! {  }`
+   = note: to `my_faulty_macro! (bcd) ;`
+   = note: expanding `my_faulty_macro! { bcd }`
+
+error: recursion limit reached while expanding `my_recursive_macro!`
+  --> $DIR/trace_faulty_macros.rs:22:9
+   |
+LL |         my_recursive_macro!();
+   |         ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     my_recursive_macro!();
+   |     --------------------- in this macro invocation
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "8"]` attribute to your crate (`trace_faulty_macros`)
+   = note: this error originates in the macro `my_recursive_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: trace_macro
+  --> $DIR/trace_faulty_macros.rs:32:5
+   |
+LL |     my_recursive_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: expanding `my_recursive_macro! {  }`
+   = note: to `my_recursive_macro! () ;`
+   = note: expanding `my_recursive_macro! {  }`
+   = note: to `my_recursive_macro! () ;`
+   = note: expanding `my_recursive_macro! {  }`
+   = note: to `my_recursive_macro! () ;`
+   = note: expanding `my_recursive_macro! {  }`
+   = note: to `my_recursive_macro! () ;`
+
+error: expected expression, found `A { a: a, b: 0, c: _, .. }`
+  --> $DIR/trace_faulty_macros.rs:16:9
+   |
+LL |         $a
+   |         ^^ expected expression
+...
+LL |     let a = pat_macro!();
+   |             ------------ in this macro invocation
+   |
+   = note: this error originates in the macro `pat_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0774]: `derive` may only be applied to `struct`s, `enum`s and `union`s
+  --> $DIR/trace_faulty_macros.rs:42:1
+   |
+LL | #[derive(Debug)]
+   | ^^^^^^^^^^^^^^^^ not applicable here
+LL | fn use_derive_macro_as_attr() {}
+   | -------------------------------- not a `struct`, `enum` or `union`
+
+note: trace_macro
+  --> $DIR/trace_faulty_macros.rs:36:13
+   |
+LL |     let a = pat_macro!();
+   |             ^^^^^^^^^^^^
+   |
+   = note: expanding `pat_macro! {  }`
+   = note: to `pat_macro! (A { a : a, b : 0, c : _, .. }) ;`
+   = note: expanding `pat_macro! { A { a : a, b : 0, c : _, .. } }`
+   = note: to `A { a: a, b: 0, c: _, .. }`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0774`.
diff --git a/tests/ui/macros/trace_macros-format.rs b/tests/ui/macros/trace_macros-format.rs
new file mode 100644
index 00000000000..afca45ca0f2
--- /dev/null
+++ b/tests/ui/macros/trace_macros-format.rs
@@ -0,0 +1,18 @@
+#![feature(trace_macros)]
+
+fn main() {
+    trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false`
+    trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false`
+    trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false`
+    trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false`
+    trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false`
+    trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false`
+
+
+    // should be fine:
+    macro_rules! expando {
+        ($x: ident) => { trace_macros!($x) }
+    }
+
+    expando!(true);
+}
diff --git a/tests/ui/macros/trace_macros-format.stderr b/tests/ui/macros/trace_macros-format.stderr
new file mode 100644
index 00000000000..c32027086aa
--- /dev/null
+++ b/tests/ui/macros/trace_macros-format.stderr
@@ -0,0 +1,38 @@
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:4:5
+   |
+LL |     trace_macros!();
+   |     ^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:5:5
+   |
+LL |     trace_macros!(1);
+   |     ^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:6:5
+   |
+LL |     trace_macros!(ident);
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:7:5
+   |
+LL |     trace_macros!(for);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:8:5
+   |
+LL |     trace_macros!(true,);
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+  --> $DIR/trace_macros-format.rs:9:5
+   |
+LL |     trace_macros!(false 1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/macros/try-macro.rs b/tests/ui/macros/try-macro.rs
new file mode 100644
index 00000000000..824c77d9de5
--- /dev/null
+++ b/tests/ui/macros/try-macro.rs
@@ -0,0 +1,49 @@
+// run-pass
+#![allow(deprecated)] // for deprecated `try!()` macro
+use std::num::{ParseFloatError, ParseIntError};
+
+fn main() {
+    assert_eq!(simple(), Ok(1));
+    assert_eq!(nested(), Ok(2));
+    assert_eq!(merge_ok(), Ok(3.0));
+    assert_eq!(merge_int_err(), Err(Error::Int));
+    assert_eq!(merge_float_err(), Err(Error::Float));
+}
+
+fn simple() -> Result<i32, ParseIntError> {
+    Ok(try!("1".parse()))
+}
+
+fn nested() -> Result<i32, ParseIntError> {
+    Ok(try!(try!("2".parse::<i32>()).to_string().parse::<i32>()))
+}
+
+fn merge_ok() -> Result<f32, Error> {
+    Ok(try!("1".parse::<i32>()) as f32 + try!("2.0".parse::<f32>()))
+}
+
+fn merge_int_err() -> Result<f32, Error> {
+    Ok(try!("a".parse::<i32>()) as f32 + try!("2.0".parse::<f32>()))
+}
+
+fn merge_float_err() -> Result<f32, Error> {
+    Ok(try!("1".parse::<i32>()) as f32 + try!("b".parse::<f32>()))
+}
+
+#[derive(Debug, PartialEq)]
+enum Error {
+    Int,
+    Float,
+}
+
+impl From<ParseIntError> for Error {
+    fn from(_: ParseIntError) -> Error {
+        Error::Int
+    }
+}
+
+impl From<ParseFloatError> for Error {
+    fn from(_: ParseFloatError) -> Error {
+        Error::Float
+    }
+}
diff --git a/tests/ui/macros/two-macro-use.rs b/tests/ui/macros/two-macro-use.rs
new file mode 100644
index 00000000000..07022bb01e3
--- /dev/null
+++ b/tests/ui/macros/two-macro-use.rs
@@ -0,0 +1,11 @@
+// run-pass
+// aux-build:two_macros.rs
+
+#[macro_use(macro_one)]
+#[macro_use(macro_two)]
+extern crate two_macros;
+
+pub fn main() {
+    macro_one!();
+    macro_two!();
+}
diff --git a/tests/ui/macros/type-macros-hlist.rs b/tests/ui/macros/type-macros-hlist.rs
new file mode 100644
index 00000000000..946b5bd5d93
--- /dev/null
+++ b/tests/ui/macros/type-macros-hlist.rs
@@ -0,0 +1,80 @@
+// run-pass
+#![allow(unused_macro_rules)]
+
+use std::ops::*;
+
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+struct Nil;
+ // empty HList
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+struct Cons<H, T: HList>(H, T);
+ // cons cell of HList
+
+ // trait to classify valid HLists
+trait HList { }
+impl HList for Nil { }
+impl <H, T: HList> HList for Cons<H, T> { }
+
+// term-level macro for HLists
+macro_rules! hlist({  } => { Nil } ; { $ head : expr } => {
+                   Cons ( $ head , Nil ) } ; {
+                   $ head : expr , $ ( $ tail : expr ) , * } => {
+                   Cons ( $ head , hlist ! ( $ ( $ tail ) , * ) ) } ;);
+
+// type-level macro for HLists
+macro_rules! HList({  } => { Nil } ; { $ head : ty } => {
+                   Cons < $ head , Nil > } ; {
+                   $ head : ty , $ ( $ tail : ty ) , * } => {
+                   Cons < $ head , HList ! ( $ ( $ tail ) , * ) > } ;);
+
+// nil case for HList append
+impl <Ys: HList> Add<Ys> for Nil {
+    type
+    Output
+    =
+    Ys;
+
+    fn add(self, rhs: Ys) -> Ys { rhs }
+}
+
+// cons case for HList append
+impl <Rec: HList + Sized, X, Xs: HList, Ys: HList> Add<Ys> for Cons<X, Xs>
+ where Xs: Add<Ys, Output = Rec> {
+    type
+    Output
+    =
+    Cons<X, Rec>;
+
+    fn add(self, rhs: Ys) -> Cons<X, Rec> { Cons(self.0, self.1 + rhs) }
+}
+
+// type macro Expr allows us to expand the + operator appropriately
+macro_rules! Expr({ ( $ ( $ LHS : tt ) + ) } => { Expr ! ( $ ( $ LHS ) + ) } ;
+                  { HList ! [ $ ( $ LHS : tt ) * ] + $ ( $ RHS : tt ) + } => {
+                  < Expr ! ( HList ! [ $ ( $ LHS ) * ] ) as Add < Expr ! (
+                  $ ( $ RHS ) + ) >> :: Output } ; {
+                  $ LHS : tt + $ ( $ RHS : tt ) + } => {
+                  < Expr ! ( $ LHS ) as Add < Expr ! ( $ ( $ RHS ) + ) >> ::
+                  Output } ; { $ LHS : ty } => { $ LHS } ;);
+
+// test demonstrating term level `xs + ys` and type level `Expr!(Xs + Ys)`
+fn main() {
+    fn aux<Xs: HList, Ys: HList>(xs: Xs, ys: Ys) -> Expr!(Xs + Ys) where
+     Xs: Add<Ys> {
+        xs + ys
+    }
+
+    let xs: HList!(& str , bool , Vec < u64 >) =
+        hlist!("foo" , false , vec ! [  ]);
+    let ys: HList!(u64 , [ u8 ; 3 ] , (  )) =
+        hlist!(0 , [ 0 , 1 , 2 ] , (  ));
+
+    // demonstrate recursive expansion of Expr!
+    let zs:
+            Expr!((
+                  HList ! [ & str ] + HList ! [ bool ] + HList ! [ Vec < u64 >
+                  ] ) + ( HList ! [ u64 ] + HList ! [ [ u8 ; 3 ] , (  ) ] ) +
+                  HList ! [  ]) = aux(xs, ys);
+    assert_eq!(zs , hlist ! [
+               "foo" , false , vec ! [  ] , 0 , [ 0 , 1 , 2 ] , (  ) ])
+}
diff --git a/tests/ui/macros/type-macros-simple.rs b/tests/ui/macros/type-macros-simple.rs
new file mode 100644
index 00000000000..dd3ad2ef0ac
--- /dev/null
+++ b/tests/ui/macros/type-macros-simple.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+macro_rules! Tuple {
+    { $A:ty,$B:ty } => { ($A, $B) }
+}
+
+fn main() {
+    let x: Tuple!(i32, i32) = (1, 2);
+}
+
+fn issue_36540() {
+    let i32 = 0;
+    macro_rules! m { () => { i32 } }
+    struct S<T = m!()>(m!(), T) where T: Trait<m!()>;
+
+    let x: m!() = m!();
+    std::cell::Cell::<m!()>::new(m!());
+    impl<T> std::ops::Index<m!()> for dyn Trait<(m!(), T)>
+        where T: Trait<m!()>
+    {
+        type Output = m!();
+        fn index(&self, i: m!()) -> &m!() {
+            unimplemented!()
+        }
+    }
+}
+
+trait Trait<T> {}
+impl Trait<i32> for i32 {}
diff --git a/tests/ui/macros/typeck-macro-interaction-issue-8852.rs b/tests/ui/macros/typeck-macro-interaction-issue-8852.rs
new file mode 100644
index 00000000000..f2b089b74b5
--- /dev/null
+++ b/tests/ui/macros/typeck-macro-interaction-issue-8852.rs
@@ -0,0 +1,30 @@
+// run-pass
+#![allow(dead_code)]
+
+enum T {
+    A(isize),
+    B(f64)
+}
+
+// after fixing #9384 and implementing hygiene for match bindings,
+// this now fails because the insertion of the 'y' into the match
+// doesn't cause capture. Making this macro hygienic (as I've done)
+// could very well make this test case completely pointless....
+
+macro_rules! test {
+    ($id1:ident, $id2:ident, $e:expr) => (
+        fn foo(a:T, b:T) -> T {
+            match (a, b) {
+                (T::A($id1), T::A($id2)) => T::A($e),
+                (T::B($id1), T::B($id2)) => T::B($e),
+                _ => panic!()
+            }
+        }
+    )
+}
+
+test!(x,y,x + y);
+
+pub fn main() {
+    foo(T::A(1), T::A(2));
+}
diff --git a/tests/ui/macros/unimplemented-macro-panic.rs b/tests/ui/macros/unimplemented-macro-panic.rs
new file mode 100644
index 00000000000..e7169903f8e
--- /dev/null
+++ b/tests/ui/macros/unimplemented-macro-panic.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:not implemented
+// ignore-emscripten no processes
+
+fn main() {
+    unimplemented!()
+}
diff --git a/tests/ui/macros/unknown-builtin.rs b/tests/ui/macros/unknown-builtin.rs
new file mode 100644
index 00000000000..16f9139e647
--- /dev/null
+++ b/tests/ui/macros/unknown-builtin.rs
@@ -0,0 +1,14 @@
+// error-pattern: attempted to define built-in macro more than once
+
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown`
+
+#[rustc_builtin_macro]
+macro_rules! line { () => () } //~ NOTE previously defined here
+
+fn main() {
+    line!();
+    std::prelude::v1::line!();
+}
diff --git a/tests/ui/macros/unknown-builtin.stderr b/tests/ui/macros/unknown-builtin.stderr
new file mode 100644
index 00000000000..22f54e04e54
--- /dev/null
+++ b/tests/ui/macros/unknown-builtin.stderr
@@ -0,0 +1,18 @@
+error: cannot find a built-in macro with name `unknown`
+  --> $DIR/unknown-builtin.rs:6:1
+   |
+LL | macro_rules! unknown { () => () }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0773]: attempted to define built-in macro more than once
+  --> $SRC_DIR/core/src/macros/mod.rs:LL:COL
+   |
+note: previously defined here
+  --> $DIR/unknown-builtin.rs:9:1
+   |
+LL | macro_rules! line { () => () }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0773`.
diff --git a/tests/ui/macros/unreachable-arg.edition_2021.stderr b/tests/ui/macros/unreachable-arg.edition_2021.stderr
new file mode 100644
index 00000000000..d70ef31eed6
--- /dev/null
+++ b/tests/ui/macros/unreachable-arg.edition_2021.stderr
@@ -0,0 +1,13 @@
+error: format argument must be a string literal
+  --> $DIR/unreachable-arg.rs:15:18
+   |
+LL |     unreachable!(a);
+   |                  ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     unreachable!("{}", a);
+   |                  +++++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/unreachable-arg.rs b/tests/ui/macros/unreachable-arg.rs
new file mode 100644
index 00000000000..4024bd20b79
--- /dev/null
+++ b/tests/ui/macros/unreachable-arg.rs
@@ -0,0 +1,16 @@
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]run-fail
+// [edition_2021]check-fail
+// [edition_2015]error-pattern:internal error: entered unreachable code: hello
+// [edition_2021]error-pattern:format argument must be a string literal
+
+#![allow(non_fmt_panics)]
+
+fn main() {
+    let a = "hello";
+    unreachable!(a);
+}
diff --git a/tests/ui/macros/unreachable-fmt-msg.rs b/tests/ui/macros/unreachable-fmt-msg.rs
new file mode 100644
index 00000000000..eb17ed92711
--- /dev/null
+++ b/tests/ui/macros/unreachable-fmt-msg.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:internal error: entered unreachable code: 6 is not prime
+// ignore-emscripten no processes
+
+fn main() {
+    unreachable!("{} is not {}", 6u32, "prime");
+}
diff --git a/tests/ui/macros/unreachable-format-arg.rs b/tests/ui/macros/unreachable-format-arg.rs
new file mode 100644
index 00000000000..ff059ad9e15
--- /dev/null
+++ b/tests/ui/macros/unreachable-format-arg.rs
@@ -0,0 +1,15 @@
+// run-fail
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x}
+// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5
+
+#![allow(non_fmt_panics)]
+
+fn main() {
+    let x = 5;
+    unreachable!("x is {x}");
+}
diff --git a/tests/ui/macros/unreachable-format-args.edition_2015.stderr b/tests/ui/macros/unreachable-format-args.edition_2015.stderr
new file mode 100644
index 00000000000..2cc2e134bfd
--- /dev/null
+++ b/tests/ui/macros/unreachable-format-args.edition_2015.stderr
@@ -0,0 +1,12 @@
+error: there is no argument named `x`
+  --> $DIR/unreachable-format-args.rs:13:5
+   |
+LL |     unreachable!("x is {x} and y is {y}", y = 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: did you intend to capture a variable `x` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+   = note: this error originates in the macro `$crate::concat` which comes from the expansion of the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/tests/ui/macros/unreachable-format-args.rs b/tests/ui/macros/unreachable-format-args.rs
new file mode 100644
index 00000000000..04a31fc1ba3
--- /dev/null
+++ b/tests/ui/macros/unreachable-format-args.rs
@@ -0,0 +1,14 @@
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]check-fail
+// [edition_2021]run-fail
+// [edition_2015]error-pattern:there is no argument named `x`
+// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5 and y is 0
+
+fn main() {
+    let x = 5;
+    unreachable!("x is {x} and y is {y}", y = 0);
+}
diff --git a/tests/ui/macros/unreachable-macro-panic.rs b/tests/ui/macros/unreachable-macro-panic.rs
new file mode 100644
index 00000000000..55e2102e2cc
--- /dev/null
+++ b/tests/ui/macros/unreachable-macro-panic.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:internal error: entered unreachable code
+// ignore-emscripten no processes
+
+fn main() {
+    unreachable!()
+}
diff --git a/tests/ui/macros/unreachable-static-msg.rs b/tests/ui/macros/unreachable-static-msg.rs
new file mode 100644
index 00000000000..55edf3af7d9
--- /dev/null
+++ b/tests/ui/macros/unreachable-static-msg.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:internal error: entered unreachable code: uhoh
+// ignore-emscripten no processes
+
+fn main() {
+    unreachable!("uhoh")
+}
diff --git a/tests/ui/macros/unreachable.rs b/tests/ui/macros/unreachable.rs
new file mode 100644
index 00000000000..55e2102e2cc
--- /dev/null
+++ b/tests/ui/macros/unreachable.rs
@@ -0,0 +1,7 @@
+// run-fail
+// error-pattern:internal error: entered unreachable code
+// ignore-emscripten no processes
+
+fn main() {
+    unreachable!()
+}
diff --git a/tests/ui/macros/use-macro-self.rs b/tests/ui/macros/use-macro-self.rs
new file mode 100644
index 00000000000..06464ab0bc9
--- /dev/null
+++ b/tests/ui/macros/use-macro-self.rs
@@ -0,0 +1,12 @@
+// run-pass
+#![allow(unused_imports)]
+// aux-build:use-macro-self.rs
+
+#[macro_use]
+extern crate use_macro_self;
+
+use use_macro_self::foobarius::{self};
+
+fn main() {
+    let _: () = foobarius!(); // OK, the macro returns `()`
+}
diff --git a/tests/ui/macros/vec-macro-in-pattern.rs b/tests/ui/macros/vec-macro-in-pattern.rs
new file mode 100644
index 00000000000..ce4298b8bb3
--- /dev/null
+++ b/tests/ui/macros/vec-macro-in-pattern.rs
@@ -0,0 +1,10 @@
+// This is a regression test for #61933
+// Verify that the vec![] macro may not be used in patterns
+// and that the resulting diagnostic is actually helpful.
+
+fn main() {
+    match Some(vec![42]) {
+        Some(vec![43]) => {} //~ ERROR arbitrary expressions aren't allowed in patterns
+        _ => {}
+    }
+}
diff --git a/tests/ui/macros/vec-macro-in-pattern.stderr b/tests/ui/macros/vec-macro-in-pattern.stderr
new file mode 100644
index 00000000000..7060f5d8b47
--- /dev/null
+++ b/tests/ui/macros/vec-macro-in-pattern.stderr
@@ -0,0 +1,10 @@
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/vec-macro-in-pattern.rs:7:14
+   |
+LL |         Some(vec![43]) => {}
+   |              ^^^^^^^^
+   |
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+