summaryrefslogtreecommitdiffstats
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.stderr39
-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.stderr35
-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.stderr99
-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.stderr50
-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, 16528 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 000000000..216b9dd05
--- /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 000000000..330aa6acf
--- /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 000000000..23c054808
--- /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 000000000..accbd2d1e
--- /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 000000000..5e505c30b
--- /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 000000000..57858b348
--- /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 000000000..00823216b
--- /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 000000000..c7f05d763
--- /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 000000000..578ef5632
--- /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 000000000..b8d319d85
--- /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 000000000..753675872
--- /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 000000000..dc5274a7e
--- /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 000000000..fd8cd5a1a
--- /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 000000000..fc0472b99
--- /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 000000000..4f507d7b5
--- /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 000000000..89b3a4c9d
--- /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 000000000..e8a86e3da
--- /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 000000000..da725e19e
--- /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 000000000..1e73320e4
--- /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 000000000..1e73320e4
--- /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 000000000..a314db907
--- /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 000000000..51d8f28a3
--- /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 000000000..51d8f28a3
--- /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 000000000..d4d1a3ee7
--- /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 000000000..53721053b
--- /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 000000000..bb3a5c94d
--- /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 000000000..9b388675c
--- /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 000000000..4956907c5
--- /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 000000000..657a7252a
--- /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 000000000..bbe6a48c5
--- /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 000000000..26d4c96d5
--- /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 000000000..9e190b542
--- /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 000000000..0c0d9e43c
--- /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 000000000..4f2f41f2c
--- /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 000000000..1e1a6126a
--- /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 000000000..6a452c185
--- /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 000000000..cab747c2c
--- /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 000000000..db8e92018
--- /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 000000000..7394f194b
--- /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 000000000..7d54745e0
--- /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 000000000..c267eefde
--- /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 000000000..2e2440462
--- /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 000000000..d71af9ee6
--- /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 000000000..b015500df
--- /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 000000000..a319c405e
--- /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 000000000..0497e4ae0
--- /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 000000000..1331480d8
--- /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 000000000..441a978dd
--- /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 000000000..2330c75c8
--- /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 000000000..3aadd4b0c
--- /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 000000000..f1307411a
--- /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 000000000..263cd074d
--- /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 000000000..4316fd312
--- /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 000000000..aaa9e243a
--- /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 000000000..fc9bb82b7
--- /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 000000000..c107ddd5d
--- /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 000000000..7654d8c44
--- /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 000000000..f609c4943
--- /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 000000000..bbdd465d5
--- /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 000000000..a52fc5e3d
--- /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 000000000..01691a82d
--- /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 000000000..56af618d4
--- /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 000000000..c1a4e32a6
--- /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 000000000..ba6261011
--- /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 000000000..2083f9ba3
--- /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 000000000..2aac50a9d
--- /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 000000000..2633d5f72
--- /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 000000000..eb1872cc7
--- /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 000000000..db5d3cab0
--- /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 000000000..d6cd1a3d1
--- /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 000000000..fd8f99417
--- /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 000000000..0c30a39d6
--- /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 000000000..d7ab7d626
--- /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 000000000..61fb9de1e
--- /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 000000000..8665da897
--- /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 000000000..ed67142ce
--- /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 000000000..0729e14d5
--- /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 000000000..e0a4f3878
--- /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 000000000..ebbce528a
--- /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 000000000..c4b5f68dd
--- /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 000000000..588fbe61b
--- /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 000000000..2a726efe8
--- /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 000000000..9de39e9b5
--- /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 000000000..5242f7830
--- /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 000000000..35f0f4290
--- /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 000000000..58accea27
--- /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 000000000..040894712
--- /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 000000000..3d78ed4a4
--- /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 000000000..97a2edd39
--- /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 000000000..d959329b9
--- /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 000000000..339ccbc33
--- /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 000000000..287cd7d67
--- /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 000000000..59323828b
--- /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 000000000..ac65838f2
--- /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 000000000..7971c2ab2
--- /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 000000000..ffa7a2817
--- /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 000000000..f9ea4c633
--- /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 000000000..56382b101
--- /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 000000000..fad87fa2a
--- /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 000000000..26e90edce
--- /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 000000000..3c26ec65a
--- /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 000000000..26f00fed9
--- /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 000000000..aa6380bd2
--- /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 000000000..84d8b6960
--- /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 000000000..0f4c29ec0
--- /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 000000000..80eecf8f1
--- /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 000000000..6e50afa07
--- /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 000000000..2cb45dc12
--- /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 000000000..aac589193
--- /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 000000000..e0b8855a3
--- /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 000000000..fa05baed7
--- /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 000000000..61e322afc
--- /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 000000000..24150376e
--- /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 000000000..8807279c2
--- /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 000000000..da12c3814
--- /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 000000000..e898af7fa
--- /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 000000000..f536d8f94
--- /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 000000000..cc0484458
--- /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 000000000..00acc20fc
--- /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 000000000..64280219d
--- /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 000000000..d98c5912a
--- /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 000000000..ae1ae1426
--- /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 000000000..ae623929d
--- /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 000000000..17014c6ce
--- /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 000000000..fdf5a2fca
--- /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 000000000..65b29bba8
--- /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 000000000..ea042a6c7
--- /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 000000000..39dbdd753
--- /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 000000000..c1dc80eb7
--- /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 000000000..d16252686
--- /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 000000000..f83e19213
--- /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 000000000..ac4c1da5c
--- /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 000000000..fd2378dbc
--- /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 000000000..0d6669146
--- /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 000000000..157c58c45
--- /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 000000000..d78139365
--- /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 000000000..00139662d
--- /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 000000000..ac4c16306
--- /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 000000000..f2065689f
--- /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 000000000..9ec9d48d1
--- /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 000000000..85ed97663
--- /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 000000000..828a7f459
--- /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 000000000..a8e31a648
--- /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 000000000..62e7dff54
--- /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 000000000..2229f2c39
--- /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 000000000..3886a70bb
--- /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 000000000..25e08ef85
--- /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 000000000..c9713c157
--- /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 000000000..24696d86d
--- /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 000000000..e06873b50
--- /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 000000000..bccfdc611
--- /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 000000000..a73054c92
--- /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 000000000..5f9b0e31d
--- /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 000000000..396a91994
--- /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 000000000..21b2e6826
--- /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 000000000..c4760bc02
--- /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 000000000..4792bdd64
--- /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 000000000..c25bedf37
--- /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 000000000..f178cd30c
--- /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 000000000..b24d7e1f6
--- /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 000000000..bbbca211b
--- /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 000000000..ebeb3fe07
--- /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 000000000..0a02ac8c4
--- /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 000000000..97e71c9a1
--- /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 000000000..b1f0896f3
--- /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 000000000..18df3f6ee
--- /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 000000000..18205c343
--- /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 000000000..1760ba158
--- /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 000000000..cdfe7934a
--- /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 000000000..9b7babdbb
--- /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 000000000..aa8bac13b
--- /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 000000000..34aa571c1
--- /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 000000000..5a2af45d0
--- /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 000000000..6b36c730b
--- /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 000000000..738f711f0
--- /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 000000000..b75cdce0c
--- /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 000000000..0d64effc9
--- /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 000000000..6af5b1868
--- /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 000000000..25f1d6500
--- /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 000000000..7ab3685c5
--- /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 000000000..24da2620c
--- /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 000000000..fb40cd538
--- /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 000000000..52e6ed92e
--- /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 000000000..ec12f8c5c
--- /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 000000000..9900b8fd5
--- /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 000000000..2a4e97f0e
--- /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 000000000..407094d55
--- /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 000000000..e76b09d4b
--- /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 000000000..7b32a33ea
--- /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 000000000..919eca4f9
--- /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 000000000..53a0a0793
--- /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 000000000..c376f2067
--- /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 000000000..9d1fae7a2
--- /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 000000000..602eb5974
--- /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 000000000..14a8cbe01
--- /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 000000000..d26200295
--- /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 000000000..1935de02b
--- /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 000000000..c5f7f7235
--- /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 000000000..1ef70f87a
--- /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 000000000..71c768320
--- /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 000000000..29ccd17e0
--- /dev/null
+++ b/tests/ui/macros/issue-84195-lint-anon-const.stderr
@@ -0,0 +1,39 @@
+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
+
+Future incompatibility report: Future breakage diagnostic:
+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)
+
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 000000000..53f134c26
--- /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 000000000..7a1e62d49
--- /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 000000000..e266617bd
--- /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 000000000..b556b24d6
--- /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 000000000..01e0a20a5
--- /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 000000000..eed755366
--- /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 000000000..ea7525d44
--- /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 000000000..a40e2c5f9
--- /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 000000000..14e2f6606
--- /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 000000000..f7f5b5648
--- /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 000000000..60ba2eab7
--- /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`
+//~| HELP 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`
+ //~| HELP 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 000000000..fe8a1deae
--- /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!();
+ | ^^^
+ |
+ = help: 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)]
+ | ^^^
+ |
+ = help: 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 000000000..faacfe5f8
--- /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 000000000..f1daaeb74
--- /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 000000000..5359f68cd
--- /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 000000000..a2fe402bc
--- /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 000000000..905c14dc5
--- /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 000000000..c260148c1
--- /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 000000000..e46e22f00
--- /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 000000000..2c3b099af
--- /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 000000000..c93451c76
--- /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 000000000..40d26d08c
--- /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 000000000..f3be9c628
--- /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 000000000..e7cf60876
--- /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 000000000..9185dbff6
--- /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 000000000..9e0e1b80e
--- /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 000000000..eebcfc2ef
--- /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 000000000..eefb28dee
--- /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 000000000..f8e847563
--- /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 000000000..13cecc3a3
--- /dev/null
+++ b/tests/ui/macros/lint-trailing-macro-call.stderr
@@ -0,0 +1,35 @@
+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
+
+Future incompatibility report: Future breakage diagnostic:
+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)
+
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 000000000..396748109
--- /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 000000000..68b278fd3
--- /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 000000000..2d78ae6f9
--- /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 000000000..b28b04f64
--- /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 000000000..a315981b6
--- /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 000000000..6781c9a9e
--- /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 000000000..66597c0ac
--- /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 000000000..f68100d45
--- /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 000000000..7c45b85bc
--- /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 000000000..b37f38530
--- /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 000000000..886a25bbc
--- /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 000000000..696520b28
--- /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 000000000..f01e5c44a
--- /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 000000000..88834a967
--- /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 000000000..3316d3872
--- /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 000000000..d382e8b71
--- /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 000000000..9501e7cd0
--- /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 000000000..aa8f06a0d
--- /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 000000000..13d80163d
--- /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 000000000..dadedfbe8
--- /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 000000000..859dd019d
--- /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 000000000..b4e2883e8
--- /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 000000000..a6c9dd6e1
--- /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 000000000..8406b4e78
--- /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 000000000..ac15e9fa8
--- /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 000000000..27d50ff3d
--- /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 000000000..7fd060e22
--- /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 000000000..25b8c3cc6
--- /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 000000000..7df5b6233
--- /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 000000000..874efccd3
--- /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 000000000..d09fdf118
--- /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 000000000..7785f4159
--- /dev/null
+++ b/tests/ui/macros/macro-context.stderr
@@ -0,0 +1,99 @@
+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`.
+Future incompatibility report: Future breakage diagnostic:
+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)
+
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 000000000..514b33e38
--- /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 000000000..67899556f
--- /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 000000000..1eca0186d
--- /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 000000000..87bd397f0
--- /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 000000000..4b1056fc7
--- /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 000000000..5c37cac96
--- /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 000000000..e13d8e1fc
--- /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 000000000..716a8ced5
--- /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 000000000..89f222b05
--- /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 000000000..a7f327cf5
--- /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 000000000..07849d7ce
--- /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 000000000..fcc64cc06
--- /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 000000000..ff5a5793b
--- /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 000000000..a003bff3c
--- /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 000000000..59ed79e91
--- /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 000000000..2539a6d51
--- /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 000000000..e69de29bb
--- /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 000000000..cff110470
--- /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 000000000..20da58a7e
--- /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 000000000..38f4937c1
--- /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 000000000..8b3f7ca88
--- /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 000000000..1f23e90b6
--- /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 000000000..eeb1ddd84
--- /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 000000000..ca9365563
--- /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 000000000..8054418d9
--- /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 000000000..61ae79d23
--- /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 000000000..b73742f77
--- /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 000000000..7097979ae
--- /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 000000000..71d59d8d3
--- /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 000000000..9423f0a35
--- /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 000000000..d0312c485
--- /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 000000000..f22caf279
--- /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 000000000..1a056e582
--- /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 000000000..3f492b141
--- /dev/null
+++ b/tests/ui/macros/macro-in-expression-context.stderr
@@ -0,0 +1,50 @@
+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
+
+Future incompatibility report: Future breakage diagnostic:
+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)
+
diff --git a/tests/ui/macros/macro-in-fn.rs b/tests/ui/macros/macro-in-fn.rs
new file mode 100644
index 000000000..d354fe4a7
--- /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 000000000..332bf59c9
--- /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 000000000..a8cda2307
--- /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 000000000..77b648615
--- /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 000000000..9a5bdb08a
--- /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 000000000..542486927
--- /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 000000000..35003a79a
--- /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 000000000..dc4d75096
--- /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 000000000..b04734482
--- /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 000000000..8f9dcb947
--- /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 000000000..ea3f74c9a
--- /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 000000000..59017da3b
--- /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 000000000..8552c4b81
--- /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 000000000..5931fe009
--- /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 000000000..3c2e71f9c
--- /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 000000000..2e4f88f9a
--- /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 000000000..fb8cab279
--- /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 000000000..5d9eb55fe
--- /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 000000000..ef7261c02
--- /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 000000000..bc6938d4a
--- /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 000000000..4cbc252ae
--- /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 000000000..342fad5f6
--- /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 000000000..290d7615e
--- /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 000000000..e7c37c8dd
--- /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 000000000..c1e6ba746
--- /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 000000000..3b9e716e1
--- /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 000000000..210c85ebb
--- /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 000000000..2aa1e58f6
--- /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 000000000..3b6dfd9bc
--- /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 000000000..7d39dc0a5
--- /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 000000000..3ad1297ff
--- /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 000000000..1ddc419d3
--- /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 000000000..d7c8aaae2
--- /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 000000000..9b6cd1916
--- /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 000000000..a83c5b2e4
--- /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 000000000..f1433cbf4
--- /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 000000000..5d4758a0c
--- /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 000000000..26e1f2afa
--- /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 000000000..e1ed87f94
--- /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 000000000..36aa74f08
--- /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 000000000..ec551d6cd
--- /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 000000000..b0d56e9bb
--- /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 000000000..9e24b5106
--- /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 000000000..e04dfefa4
--- /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 000000000..0752f7e31
--- /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 000000000..4ea760ab8
--- /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 000000000..5609f84e1
--- /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 000000000..24e3e89ea
--- /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 000000000..ce2911de9
--- /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 000000000..8e02789fd
--- /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 000000000..79c68fd25
--- /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 000000000..f5a97eca2
--- /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 000000000..a06487be3
--- /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 000000000..54bd13d7e
--- /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 000000000..baf816e53
--- /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 000000000..b4be03aad
--- /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 000000000..c3754dde0
--- /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 000000000..d93792bdf
--- /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 000000000..f8377ffb3
--- /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 000000000..816a3c4cc
--- /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 000000000..9574b7a1e
--- /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 000000000..68eb350a9
--- /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 000000000..f1c3512bc
--- /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 000000000..0f93fcdaa
--- /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 000000000..dfd6818b6
--- /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 000000000..7cf346286
--- /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 000000000..d71812000
--- /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 000000000..4a864c2e9
--- /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 000000000..6c011c897
--- /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 000000000..7b02a70be
--- /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 000000000..874c94d08
--- /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 000000000..475a586dd
--- /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 000000000..8f0f4fd4a
--- /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 000000000..b2a639218
--- /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 000000000..7f956dd7d
--- /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 000000000..a052b43ac
--- /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 000000000..2d02b9528
--- /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 000000000..ed7618a67
--- /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 000000000..2cfdb52b1
--- /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 000000000..a643e50e9
--- /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 000000000..c9a0b879a
--- /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 000000000..528d0b28b
--- /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 000000000..080dbcfdd
--- /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 000000000..2ee41b088
--- /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 000000000..c8bd44008
--- /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 000000000..00b10dccd
--- /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 000000000..48c7b77e5
--- /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 000000000..ec0b64a10
--- /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 000000000..4e5482a51
--- /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 000000000..c5f8f62c1
--- /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 000000000..c958104ea
--- /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 000000000..ed5d1312f
--- /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 000000000..f74795e68
--- /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 000000000..5e58fc9c1
--- /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 000000000..ae3054e7b
--- /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 000000000..85b86e221
--- /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 000000000..d142b5800
--- /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 000000000..ca5f0f190
--- /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
+ |
+ = help: 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 000000000..4e943b224
--- /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 000000000..78c408102
--- /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 000000000..f7d87434d
--- /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 000000000..663f85688
--- /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 000000000..00d954d24
--- /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 000000000..bde0fe1a0
--- /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 000000000..956a66979
--- /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 000000000..6ca1eb568
--- /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 000000000..4ab16bd10
--- /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 000000000..2901a74f6
--- /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 000000000..568ae3a85
--- /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 000000000..ab14c3589
--- /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 000000000..d42f6c179
--- /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 000000000..f57d2fb4d
--- /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 000000000..adf64b089
--- /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 000000000..8ed911cbc
--- /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 000000000..c53971e24
--- /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 000000000..b7fb94785
--- /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 000000000..fad150cad
--- /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 000000000..99a2f9401
--- /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 000000000..b1aa3298b
--- /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 000000000..8393f15fc
--- /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 000000000..dfabafb0a
--- /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 000000000..92f8a7795
--- /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 000000000..81877a29e
--- /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 000000000..e7c346286
--- /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 000000000..8878b0eea
--- /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 000000000..ada643c7a
--- /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 000000000..bf4fddea1
--- /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 000000000..84fffe44d
--- /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 000000000..5bbd54390
--- /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 000000000..4148e5b88
--- /dev/null
+++ b/tests/ui/macros/not-utf8.bin
Binary files differ
diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs
new file mode 100644
index 000000000..1cb1fdcb8
--- /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 000000000..7e1f2dcad
--- /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 000000000..a0d1a9737
--- /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 000000000..dedefac5c
--- /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 000000000..8fef9b0ed
--- /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 000000000..622818a92
--- /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 000000000..66f9cdc55
--- /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 000000000..d07681453
--- /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 000000000..bc918c7a4
--- /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 000000000..ebf65f1cc
--- /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 000000000..ec036e8b1
--- /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 000000000..5dd261933
--- /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 000000000..f5cac2dfb
--- /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 000000000..b8865112e
--- /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 000000000..1151a829e
--- /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 000000000..27665bfc3
--- /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 000000000..b8b6f0846
--- /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 000000000..d46f396ee
--- /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 000000000..6a1435f79
--- /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 000000000..1f5a29ab5
--- /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 000000000..903ed507c
--- /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 000000000..01860adaa
--- /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 000000000..5ec84b08f
--- /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 000000000..90f858f80
--- /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 000000000..ab8d95a41
--- /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 000000000..ed94c27cf
--- /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 000000000..d05cd1b31
--- /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 000000000..b954967c4
--- /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 000000000..6a0d68bd6
--- /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 000000000..236122b64
--- /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 000000000..b4fef11f1
--- /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 000000000..ecf598b10
--- /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 000000000..fdf16442d
--- /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 000000000..a6cff95fd
--- /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 000000000..e0bb4d985
--- /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 000000000..bdd191e8e
--- /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 000000000..f83ace8fa
--- /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 000000000..9b9506c80
--- /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 000000000..e57347b36
--- /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 000000000..570191d2c
--- /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 000000000..5cd217df6
--- /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 000000000..ae6de3c50
--- /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 000000000..c42ee9b29
--- /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 000000000..2e929fc1d
--- /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 000000000..d752015a4
--- /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 000000000..7e46260d5
--- /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 000000000..576120811
--- /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 000000000..43272248c
--- /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 000000000..b2fdd2e19
--- /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 000000000..21e47da07
--- /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 000000000..afca45ca0
--- /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 000000000..c32027086
--- /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 000000000..824c77d9d
--- /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 000000000..07022bb01
--- /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 000000000..946b5bd5d
--- /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 000000000..dd3ad2ef0
--- /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 000000000..f2b089b74
--- /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 000000000..e7169903f
--- /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 000000000..16f9139e6
--- /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 000000000..22f54e04e
--- /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 000000000..d70ef31ee
--- /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 000000000..4024bd20b
--- /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 000000000..eb17ed927
--- /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 000000000..ff059ad9e
--- /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 000000000..2cc2e134b
--- /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 000000000..04a31fc1b
--- /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 000000000..55e2102e2
--- /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 000000000..55edf3af7
--- /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 000000000..55e2102e2
--- /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 000000000..06464ab0b
--- /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 000000000..ce4298b8b
--- /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 000000000..7060f5d8b
--- /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
+