about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-07-10 17:38:52 +0200
committerLeón Orell Valerian Liehr <me@fmease.dev>2025-02-15 16:47:30 +0100
commit9b6fd35738965ef3f246018fddc743b5e5cd8d2c (patch)
tree955710be2b114b379217abfe9c79362d99b37bbe
parent46d53a68aa1b10833ec25178171f34e29e71f1f1 (diff)
downloadrust-9b6fd35738965ef3f246018fddc743b5e5cd8d2c.tar.gz
rust-9b6fd35738965ef3f246018fddc743b5e5cd8d2c.zip
Reject macro calls inside of `#![crate_name]`
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs10
-rw-r--r--compiler/rustc_expand/src/module.rs12
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs10
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs5
-rw-r--r--compiler/rustc_interface/messages.ftl4
-rw-r--r--compiler/rustc_interface/src/errors.rs15
-rw-r--r--compiler/rustc_interface/src/passes.rs105
-rw-r--r--compiler/rustc_interface/src/util.rs6
-rw-r--r--compiler/rustc_session/messages.ftl4
-rw-r--r--compiler/rustc_session/src/errors.rs15
-rw-r--r--compiler/rustc_session/src/output.rs56
-rw-r--r--tests/ui/attributes/crate-name-macro-call.rs6
-rw-r--r--tests/ui/attributes/crate-name-macro-call.stderr8
-rw-r--r--tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs5
-rw-r--r--tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr8
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs4
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr8
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs7
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr8
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs5
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr8
21 files changed, 195 insertions, 114 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 2bcc33241df..a2ddff7183e 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -667,11 +667,12 @@ fn print_crate_info(
                     return Compilation::Continue;
                 };
                 let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
-                let id = rustc_session::output::find_crate_name(sess, attrs);
+                let crate_name = passes::get_crate_name(sess, attrs);
                 let crate_types = collect_crate_types(sess, attrs);
                 for &style in &crate_types {
-                    let fname =
-                        rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
+                    let fname = rustc_session::output::filename_for_input(
+                        sess, style, crate_name, &t_outputs,
+                    );
                     println_info!("{}", fname.as_path().file_name().unwrap().to_string_lossy());
                 }
             }
@@ -680,8 +681,7 @@ fn print_crate_info(
                     // no crate attributes, print out an error and exit
                     return Compilation::Continue;
                 };
-                let id = rustc_session::output::find_crate_name(sess, attrs);
-                println_info!("{id}");
+                println_info!("{}", passes::get_crate_name(sess, attrs));
             }
             Cfg => {
                 let mut cfgs = sess
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 9c35b26772b..e925052c607 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -183,12 +183,12 @@ pub(crate) fn mod_file_path_from_attr(
     let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
     let Some(path_sym) = first_path.value_str() else {
         // This check is here mainly to catch attempting to use a macro,
-        // such as #[path = concat!(...)]. This isn't currently supported
-        // because otherwise the InvocationCollector would need to defer
-        // loading a module until the #[path] attribute was expanded, and
-        // it doesn't support that (and would likely add a bit of
-        // complexity). Usually bad forms are checked in AstValidator (via
-        // `check_builtin_attribute`), but by the time that runs the macro
+        // such as `#[path = concat!(...)]`. This isn't supported because
+        // otherwise the `InvocationCollector` would need to defer loading
+        // a module until the `#[path]` attribute was expanded, and it
+        // doesn't support that (and would likely add a bit of complexity).
+        // Usually bad forms are checked during semantic analysis via
+        // `TyCtxt::check_mod_attrs`), but by the time that runs the macro
         // is expanded, and it doesn't give an error.
         validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, first_path, sym::path);
     };
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 4ea171ab4a9..19cca48af61 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -117,8 +117,9 @@ use rustc_data_structures::{base_n, flock};
 use rustc_fs_util::{LinkOrCopy, link_or_copy, try_canonicalize};
 use rustc_middle::bug;
 use rustc_session::config::CrateType;
-use rustc_session::output::{collect_crate_types, find_crate_name};
+use rustc_session::output::collect_crate_types;
 use rustc_session::{Session, StableCrateId};
+use rustc_span::Symbol;
 use tracing::debug;
 
 use crate::errors;
@@ -211,7 +212,7 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 /// The garbage collection will take care of it.
 ///
 /// [`rustc_interface::queries::dep_graph`]: ../../rustc_interface/struct.Queries.html#structfield.dep_graph
-pub(crate) fn prepare_session_directory(sess: &Session) {
+pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) {
     if sess.opts.incremental.is_none() {
         return;
     }
@@ -221,7 +222,7 @@ pub(crate) fn prepare_session_directory(sess: &Session) {
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
-    let crate_dir = crate_path(sess);
+    let crate_dir = crate_path(sess, crate_name);
     debug!("crate-dir: {}", crate_dir.display());
     create_dir(sess, &crate_dir, "crate");
 
@@ -594,10 +595,9 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, &'static str> {
     Ok(UNIX_EPOCH + duration)
 }
 
-fn crate_path(sess: &Session) -> PathBuf {
+fn crate_path(sess: &Session, crate_name: Symbol) -> PathBuf {
     let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
 
-    let crate_name = find_crate_name(sess, &[]);
     let crate_types = collect_crate_types(sess, &[]);
     let stable_crate_id = StableCrateId::new(
         crate_name,
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 48df84f3d09..7977bcc6891 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -11,6 +11,7 @@ use rustc_serialize::Decodable;
 use rustc_serialize::opaque::MemDecoder;
 use rustc_session::Session;
 use rustc_session::config::IncrementalStateAssertion;
+use rustc_span::Symbol;
 use tracing::{debug, warn};
 
 use super::data::*;
@@ -203,9 +204,9 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
 
 /// Setups the dependency graph by loading an existing graph from disk and set up streaming of a
 /// new graph to an incremental session directory.
-pub fn setup_dep_graph(sess: &Session) -> DepGraph {
+pub fn setup_dep_graph(sess: &Session, crate_name: Symbol) -> DepGraph {
     // `load_dep_graph` can only be called after `prepare_session_directory`.
-    prepare_session_directory(sess);
+    prepare_session_directory(sess, crate_name);
 
     let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
 
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 31123625369..43c69c8e571 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -6,6 +6,10 @@ interface_abi_required_feature_issue = for more information, see issue #116344 <
 interface_cant_emit_mir =
     could not emit MIR: {$error}
 
+interface_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$crate_name}` != `{$attr_crate_name}`
+
+interface_crate_name_invalid = crate names cannot start with a `-`, but `{$crate_name}` has a leading hyphen
+
 interface_emoji_identifier =
     identifiers cannot contain emoji: `{$ident}`
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index b62950d6709..c3b858d4f2e 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -5,6 +5,21 @@ use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
+#[diag(interface_crate_name_does_not_match)]
+pub(crate) struct CrateNameDoesNotMatch {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) crate_name: Symbol,
+    pub(crate) attr_crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(interface_crate_name_invalid)]
+pub(crate) struct CrateNameInvalid<'a> {
+    pub(crate) crate_name: &'a str,
+}
+
+#[derive(Diagnostic)]
 #[diag(interface_ferris_identifier)]
 pub struct FerrisIdentifier {
     #[primary_span]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index e5adcdb244f..fcebca3ecc9 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -28,10 +28,12 @@ use rustc_passes::{abi_test, input_stats, layout_test};
 use rustc_resolve::Resolver;
 use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
 use rustc_session::cstore::Untracked;
-use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name};
+use rustc_session::output::{collect_crate_types, filename_for_input};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
-use rustc_span::{ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Symbol, sym};
+use rustc_span::{
+    ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
+};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
 use tracing::{info, instrument};
@@ -725,8 +727,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
 
     let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
 
-    // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches.
-    let crate_name = find_crate_name(sess, &pre_configured_attrs);
+    let crate_name = get_crate_name(sess, &pre_configured_attrs);
     let crate_types = collect_crate_types(sess, &pre_configured_attrs);
     let stable_crate_id = StableCrateId::new(
         crate_name,
@@ -735,7 +736,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
         sess.cfg_version,
     );
     let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
-    let dep_graph = setup_dep_graph(sess);
+    let dep_graph = setup_dep_graph(sess, crate_name);
 
     let cstore =
         FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
@@ -1080,23 +1081,85 @@ pub(crate) fn start_codegen<'tcx>(
     codegen
 }
 
-fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
-    if let Some(attr) = krate_attrs
-        .iter()
-        .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none())
+/// Compute and validate the crate name.
+pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol {
+    // We validate *all* occurrences of `#![crate_name]`, pick the first find and
+    // if a crate name was passed on the command line via `--crate-name` we enforce
+    // that they match.
+    // We perform the validation step here instead of later to ensure it gets run
+    // in all code paths that require the crate name very early on, namely before
+    // macro expansion.
+
+    let attr_crate_name =
+        validate_and_find_value_str_builtin_attr(sym::crate_name, sess, krate_attrs);
+
+    let validate = |name, span| {
+        rustc_session::output::validate_crate_name(sess, name, span);
+        name
+    };
+
+    if let Some(crate_name) = &sess.opts.crate_name {
+        let crate_name = Symbol::intern(crate_name);
+        if let Some((attr_crate_name, span)) = attr_crate_name
+            && attr_crate_name != crate_name
+        {
+            sess.dcx().emit_err(errors::CrateNameDoesNotMatch {
+                span,
+                crate_name,
+                attr_crate_name,
+            });
+        }
+        return validate(crate_name, None);
+    }
+
+    if let Some((crate_name, span)) = attr_crate_name {
+        return validate(crate_name, Some(span));
+    }
+
+    if let Input::File(ref path) = sess.io.input
+        && let Some(file_stem) = path.file_stem().and_then(|s| s.to_str())
     {
-        // This is here mainly to check for using a macro, such as
-        // #![recursion_limit = foo!()]. That is not supported since that
-        // would require expanding this while in the middle of expansion,
-        // which needs to know the limit before expanding. Otherwise,
-        // validation would normally be caught in AstValidator (via
-        // `check_builtin_attribute`), but by the time that runs the macro
-        // is expanded, and it doesn't give an error.
-        validate_attr::emit_fatal_malformed_builtin_attribute(
-            &sess.psess,
-            attr,
-            sym::recursion_limit,
-        );
+        if file_stem.starts_with('-') {
+            sess.dcx().emit_err(errors::CrateNameInvalid { crate_name: file_stem });
+        } else {
+            return validate(Symbol::intern(&file_stem.replace('-', "_")), None);
+        }
     }
+
+    sym::rust_out
+}
+
+fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
+    // We don't permit macro calls inside of the attribute (e.g., #![recursion_limit = `expand!()`])
+    // because that would require expanding this while in the middle of expansion, which needs to
+    // know the limit before expanding.
+    let _ = validate_and_find_value_str_builtin_attr(sym::recursion_limit, sess, krate_attrs);
     rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
 }
+
+/// Validate *all* occurrences of the given "[value-str]" built-in attribute and return the first find.
+///
+/// This validator is intended for built-in attributes whose value needs to be known very early
+/// during compilation (namely, before macro expansion) and it mainly exists to reject macro calls
+/// inside of the attributes, such as in `#![name = expand!()]`. Normal attribute validation happens
+/// during semantic analysis via [`TyCtxt::check_mod_attrs`] which happens *after* macro expansion
+/// when such macro calls (here: `expand`) have already been expanded and we can no longer check for
+/// their presence.
+///
+/// [value-str]: ast::Attribute::value_str
+fn validate_and_find_value_str_builtin_attr(
+    name: Symbol,
+    sess: &Session,
+    krate_attrs: &[ast::Attribute],
+) -> Option<(Symbol, Span)> {
+    let mut result = None;
+    // Validate *all* relevant attributes, not just the first occurrence.
+    for attr in ast::attr::filter_by_name(krate_attrs, name) {
+        let Some(value) = attr.value_str() else {
+            validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, attr, name)
+        };
+        // Choose the first occurrence as our result.
+        result.get_or_insert((value, attr.span));
+    }
+    result
+}
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index e900ec14fca..bc2aae7cd87 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -433,11 +433,11 @@ pub(crate) fn check_attr_crate_type(
                 }
             } else {
                 // This is here mainly to check for using a macro, such as
-                // #![crate_type = foo!()]. That is not supported since the
+                // `#![crate_type = foo!()]`. That is not supported since the
                 // crate type needs to be known very early in compilation long
                 // before expansion. Otherwise, validation would normally be
-                // caught in AstValidator (via `check_builtin_attribute`), but
-                // by the time that runs the macro is expanded, and it doesn't
+                // caught during semantic analysis via `TyCtxt::check_mod_attrs`,
+                // but by the time that runs the macro is expanded, and it doesn't
                 // give an error.
                 validate_attr::emit_fatal_malformed_builtin_attribute(
                     &sess.psess,
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index f108488cd58..74b8087e077 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -8,12 +8,8 @@ session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible
 session_cli_feature_diagnostic_help =
     add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
 
-session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$crate_name}` != `{$attr_crate_name}`
-
 session_crate_name_empty = crate name must not be empty
 
-session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
-
 session_embed_source_insufficient_dwarf_version = `-Zembed-source=y` requires at least `-Z dwarf-version=5` but DWARF version is {$dwarf_version}
 
 session_embed_source_requires_debug_info = `-Zembed-source=y` requires debug information to be enabled
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index b57560ff782..71d8dbe44fe 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -213,21 +213,6 @@ pub(crate) struct FileWriteFail<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(session_crate_name_does_not_match)]
-pub(crate) struct CrateNameDoesNotMatch {
-    #[primary_span]
-    pub(crate) span: Span,
-    pub(crate) crate_name: Symbol,
-    pub(crate) attr_crate_name: Symbol,
-}
-
-#[derive(Diagnostic)]
-#[diag(session_crate_name_invalid)]
-pub(crate) struct CrateNameInvalid<'a> {
-    pub(crate) s: &'a str,
-}
-
-#[derive(Diagnostic)]
 #[diag(session_crate_name_empty)]
 pub(crate) struct CrateNameEmpty {
     #[primary_span]
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index a6d4ebf23c7..b37a80274c0 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -2,15 +2,12 @@
 
 use std::path::Path;
 
-use rustc_ast::{self as ast, attr};
+use rustc_ast as ast;
 use rustc_span::{Span, Symbol, sym};
 
 use crate::Session;
-use crate::config::{self, CrateType, Input, OutFileName, OutputFilenames, OutputType};
-use crate::errors::{
-    self, CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
-    InvalidCharacterInCrateName,
-};
+use crate::config::{self, CrateType, OutFileName, OutputFilenames, OutputType};
+use crate::errors::{self, CrateNameEmpty, FileIsNotWriteable, InvalidCharacterInCrateName};
 
 pub fn out_filename(
     sess: &Session,
@@ -49,53 +46,6 @@ fn is_writeable(p: &Path) -> bool {
     }
 }
 
-/// Find and [validate] the crate name.
-///
-/// [validate]: validate_crate_name
-pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
-    let validate = |name, span| {
-        validate_crate_name(sess, name, span);
-        name
-    };
-
-    // Look in attributes 100% of the time to make sure the attribute is marked
-    // as used. After doing this, however, we still prioritize a crate name from
-    // the command line over one found in the #[crate_name] attribute. If we
-    // find both we ensure that they're the same later on as well.
-    let attr_crate_name =
-        attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
-
-    if let Some(crate_name) = &sess.opts.crate_name {
-        let crate_name = Symbol::intern(crate_name);
-        if let Some((attr, attr_crate_name)) = attr_crate_name
-            && attr_crate_name != crate_name
-        {
-            sess.dcx().emit_err(CrateNameDoesNotMatch {
-                span: attr.span,
-                crate_name,
-                attr_crate_name,
-            });
-        }
-        return validate(crate_name, None);
-    }
-
-    if let Some((attr, crate_name)) = attr_crate_name {
-        return validate(crate_name, Some(attr.span));
-    }
-
-    if let Input::File(ref path) = sess.io.input
-        && let Some(s) = path.file_stem().and_then(|s| s.to_str())
-    {
-        if s.starts_with('-') {
-            sess.dcx().emit_err(CrateNameInvalid { s });
-        } else {
-            return validate(Symbol::intern(&s.replace('-', "_")), None);
-        }
-    }
-
-    sym::rust_out
-}
-
 /// Validate the given crate name.
 ///
 /// Note that this validation is more permissive than identifier parsing. It considers
diff --git a/tests/ui/attributes/crate-name-macro-call.rs b/tests/ui/attributes/crate-name-macro-call.rs
new file mode 100644
index 00000000000..1aae2e506e2
--- /dev/null
+++ b/tests/ui/attributes/crate-name-macro-call.rs
@@ -0,0 +1,6 @@
+// issue: rust-lang/rust#122001
+// Ensure we reject macro calls inside `#![crate_name]` as their result wouldn't get honored anyway.
+
+#![crate_name = concat!("my", "crate")] //~ ERROR malformed `crate_name` attribute input
+
+fn main() {}
diff --git a/tests/ui/attributes/crate-name-macro-call.stderr b/tests/ui/attributes/crate-name-macro-call.stderr
new file mode 100644
index 00000000000..ab562b41a31
--- /dev/null
+++ b/tests/ui/attributes/crate-name-macro-call.stderr
@@ -0,0 +1,8 @@
+error: malformed `crate_name` attribute input
+  --> $DIR/crate-name-macro-call.rs:4:1
+   |
+LL | #![crate_name = concat!("my", "crate")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs
new file mode 100644
index 00000000000..c7f3c2c5403
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.rs
@@ -0,0 +1,5 @@
+// Ensure we validate `#![crate_name]` on print requests and reject macro calls inside of it.
+// See also <https://github.com/rust-lang/rust/issues/122001>.
+
+//@ compile-flags: --print=crate-name
+#![crate_name = concat!("wrapped")] //~ ERROR malformed `crate_name` attribute input
diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
new file mode 100644
index 00000000000..6bf09a2b131
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
@@ -0,0 +1,8 @@
+error: malformed `crate_name` attribute input
+  --> $DIR/print-crate-name-request-malformed-crate-name.rs:5:1
+   |
+LL | #![crate_name = concat!("wrapped")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs
new file mode 100644
index 00000000000..5cf1ae36b42
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.rs
@@ -0,0 +1,4 @@
+// Ensure we validate `#![crate_name]` on print requests.
+
+//@ compile-flags: --print=file-names
+#![crate_name]  //~ ERROR malformed `crate_name` attribute input
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
new file mode 100644
index 00000000000..de62aed79fc
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
@@ -0,0 +1,8 @@
+error: malformed `crate_name` attribute input
+  --> $DIR/print-file-names-request-malformed-crate-name-1.rs:4:1
+   |
+LL | #![crate_name]
+   | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs
new file mode 100644
index 00000000000..13c9d1e0027
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.rs
@@ -0,0 +1,7 @@
+// Ensure that we validate *all* `#![crate_name]`s on print requests, not just the first,
+// and that we reject macro calls inside of them.
+// See also <https://github.com/rust-lang/rust/issues/122001>.
+
+//@ compile-flags: --print=file-names
+#![crate_name = "this_one_is_okay"]
+#![crate_name = concat!("this_one_is_not")]  //~ ERROR malformed `crate_name` attribute input
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
new file mode 100644
index 00000000000..42c33de1221
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
@@ -0,0 +1,8 @@
+error: malformed `crate_name` attribute input
+  --> $DIR/print-file-names-request-malformed-crate-name-2.rs:7:1
+   |
+LL | #![crate_name = concat!("this_one_is_not")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs
new file mode 100644
index 00000000000..5fe8bd7945f
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.rs
@@ -0,0 +1,5 @@
+// Ensure we validate `#![crate_name]` on print requests and reject macro calls inside of it.
+// See also <https://github.com/rust-lang/rust/issues/122001>.
+
+//@ compile-flags: --print=file-names
+#![crate_name = concat!("wrapped")]  //~ ERROR malformed `crate_name` attribute input
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
new file mode 100644
index 00000000000..cb5ffaab9ca
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
@@ -0,0 +1,8 @@
+error: malformed `crate_name` attribute input
+  --> $DIR/print-file-names-request-malformed-crate-name.rs:5:1
+   |
+LL | #![crate_name = concat!("wrapped")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+
+error: aborting due to 1 previous error
+